From bb80fbd643a62bffb4a50d25f23ae1d72dc71b09 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 2 Jul 2016 12:04:21 -0700 Subject: [PATCH] Sync with rustc 1.11.0-nightly (01411937f 2016-07-01) --- syntex_errors/src/Cargo.toml | 14 + .../errors => syntex_errors/src}/emitter.rs | 326 +--- .../errors/mod.rs => syntex_errors/src/lib.rs | 85 +- .../src}/registry.rs | 0 .../mod.rs => syntex_errors/src/snippet.rs | 54 +- syntex_syntax/src/Cargo.toml | 2 + syntex_syntax/src/ast.rs | 480 ++---- syntex_syntax/src/attr.rs | 143 +- syntex_syntax/src/codemap.rs | 1519 ++++++++++------- syntex_syntax/src/config.rs | 17 +- syntex_syntax/src/diagnostics/metadata.rs | 2 +- syntex_syntax/src/diagnostics/plugin.rs | 7 +- syntex_syntax/src/errors/snippet/test.rs | 597 ------- syntex_syntax/src/ext/base.rs | 133 +- syntex_syntax/src/ext/build.rs | 90 +- syntex_syntax/src/ext/expand.rs | 724 ++------ syntex_syntax/src/ext/mtwt.rs | 379 +--- syntex_syntax/src/ext/quote.rs | 68 +- syntex_syntax/src/ext/source_util.rs | 25 +- syntex_syntax/src/ext/tt/macro_parser.rs | 21 +- syntex_syntax/src/ext/tt/macro_rules.rs | 66 +- syntex_syntax/src/ext/tt/transcribe.rs | 18 +- syntex_syntax/src/feature_gate.rs | 20 +- syntex_syntax/src/fold.rs | 167 +- syntex_syntax/src/{errors => }/json.rs | 16 +- syntex_syntax/src/lib.rs | 13 +- syntex_syntax/src/parse/attr.rs | 3 +- syntex_syntax/src/parse/classify.rs | 10 +- syntex_syntax/src/parse/lexer/comments.rs | 3 +- syntex_syntax/src/parse/lexer/mod.rs | 52 +- .../src/parse/lexer/unicode_chars.rs | 2 +- syntex_syntax/src/parse/mod.rs | 67 +- syntex_syntax/src/parse/obsolete.rs | 2 +- syntex_syntax/src/parse/parser.rs | 586 +++---- syntex_syntax/src/parse/token.rs | 3 +- syntex_syntax/src/print/pprust.rs | 194 ++- syntex_syntax/src/show_span.rs | 2 +- syntex_syntax/src/std_inject.rs | 4 +- syntex_syntax/src/test.rs | 14 +- syntex_syntax/src/tokenstream.rs | 210 +++ syntex_syntax/src/util/node_count.rs | 72 +- syntex_syntax/src/util/parser_testing.rs | 3 +- syntex_syntax/src/util/thin_vec.rs | 59 + syntex_syntax/src/visit.rs | 236 ++- 44 files changed, 2682 insertions(+), 3826 deletions(-) create mode 100644 syntex_errors/src/Cargo.toml rename {syntex_syntax/src/errors => syntex_errors/src}/emitter.rs (67%) rename syntex_syntax/src/errors/mod.rs => syntex_errors/src/lib.rs (92%) rename {syntex_syntax/src/diagnostics => syntex_errors/src}/registry.rs (100%) rename syntex_syntax/src/errors/snippet/mod.rs => syntex_errors/src/snippet.rs (95%) delete mode 100644 syntex_syntax/src/errors/snippet/test.rs rename syntex_syntax/src/{errors => }/json.rs (97%) create mode 100644 syntex_syntax/src/tokenstream.rs create mode 100644 syntex_syntax/src/util/thin_vec.rs diff --git a/syntex_errors/src/Cargo.toml b/syntex_errors/src/Cargo.toml new file mode 100644 index 00000000..128c270e --- /dev/null +++ b/syntex_errors/src/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_errors" +version = "0.0.0" + +[lib] +name = "rustc_errors" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +serialize = { path = "../libserialize" } +syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file diff --git a/syntex_syntax/src/errors/emitter.rs b/syntex_errors/src/emitter.rs similarity index 67% rename from syntex_syntax/src/errors/emitter.rs rename to syntex_errors/src/emitter.rs index 71a03e84..a7c68e3a 100644 --- a/syntex_syntax/src/errors/emitter.rs +++ b/syntex_errors/src/emitter.rs @@ -10,14 +10,14 @@ use self::Destination::*; -use codemap::{self, COMMAND_LINE_SP, DUMMY_SP, Span, MultiSpan}; -use diagnostics; +use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, Span, MultiSpan, LineInfo}; +use registry; -use errors::check_old_skool; -use errors::{Level, RenderSpan, CodeSuggestion, DiagnosticBuilder}; -use errors::RenderSpan::*; -use errors::Level::*; -use errors::snippet::{RenderedLineKind, SnippetData, Style}; +use check_old_skool; +use {Level, RenderSpan, CodeSuggestion, DiagnosticBuilder, CodeMapper}; +use RenderSpan::*; +use Level::*; +use snippet::{RenderedLineKind, SnippetData, Style, FormatMode}; use std::{cmp, fmt}; use std::io::prelude::*; @@ -151,15 +151,15 @@ impl BasicEmitter { pub struct EmitterWriter { dst: Destination, - registry: Option, - cm: Rc, + registry: Option, + cm: Rc, /// Is this the first error emitted thus far? If not, we emit a /// `\n` before the top-level errors. first: bool, // For now, allow an old-school mode while we transition - old_school: bool, + format_mode: FormatMode } impl CoreEmitter for EmitterWriter { @@ -193,36 +193,36 @@ macro_rules! println_maybe_styled { impl EmitterWriter { pub fn stderr(color_config: ColorConfig, - registry: Option, - code_map: Rc) + registry: Option, + code_map: Rc, + format_mode: FormatMode) -> EmitterWriter { - let old_school = check_old_skool(); if color_config.use_color() { let dst = Destination::from_stderr(); EmitterWriter { dst: dst, registry: registry, cm: code_map, first: true, - old_school: old_school } + format_mode: format_mode.clone() } } else { EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map, first: true, - old_school: old_school } + format_mode: format_mode.clone() } } } pub fn new(dst: Box, - registry: Option, - code_map: Rc) + registry: Option, + code_map: Rc, + format_mode: FormatMode) -> EmitterWriter { - let old_school = check_old_skool(); EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, first: true, - old_school: old_school } + format_mode: format_mode.clone() } } fn emit_message_(&mut self, @@ -233,11 +233,17 @@ impl EmitterWriter { is_header: bool, show_snippet: bool) -> io::Result<()> { + let old_school = match self.format_mode { + FormatMode::NewErrorFormat => false, + FormatMode::OriginalErrorFormat => true, + FormatMode::EnvironmentSelected => check_old_skool() + }; + if is_header { if self.first { self.first = false; } else { - if !self.old_school { + if !old_school { write!(self.dst, "\n")?; } } @@ -248,7 +254,7 @@ impl EmitterWriter { .and_then(|registry| registry.find_description(code)) .is_some() => { let code_with_explain = String::from("--explain ") + code; - if self.old_school { + if old_school { let loc = match rsp.span().primary_span() { Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), Some(ps) => self.cm.span_to_string(ps), @@ -261,7 +267,7 @@ impl EmitterWriter { } } _ => { - if self.old_school { + if old_school { let loc = match rsp.span().primary_span() { Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), Some(ps) => self.cm.span_to_string(ps), @@ -303,7 +309,7 @@ impl EmitterWriter { } } } - if self.old_school { + if old_school { match code { Some(code) if self.registry.as_ref() .and_then(|registry| registry.find_description(code)) @@ -326,11 +332,13 @@ impl EmitterWriter { fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()> { + use std::borrow::Borrow; + let primary_span = suggestion.msp.primary_span().unwrap(); let lines = self.cm.span_to_lines(primary_span).unwrap(); assert!(!lines.lines.is_empty()); - let complete = suggestion.splice_lines(&self.cm); + let complete = suggestion.splice_lines(self.cm.borrow()); let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES); let display_lines = &lines.lines[..line_count]; @@ -356,19 +364,27 @@ impl EmitterWriter { Ok(()) } - fn highlight_lines(&mut self, + pub fn highlight_lines(&mut self, msp: &MultiSpan, lvl: Level) -> io::Result<()> { + let old_school = match self.format_mode { + FormatMode::NewErrorFormat => false, + FormatMode::OriginalErrorFormat => true, + FormatMode::EnvironmentSelected => check_old_skool() + }; + let mut snippet_data = SnippetData::new(self.cm.clone(), - msp.primary_span()); - if self.old_school { + msp.primary_span(), + self.format_mode.clone()); + if old_school { let mut output_vec = vec![]; for span_label in msp.span_labels() { let mut snippet_data = SnippetData::new(self.cm.clone(), - Some(span_label.span)); + Some(span_label.span), + self.format_mode.clone()); snippet_data.push(span_label.span, span_label.is_primary, @@ -430,7 +446,7 @@ impl EmitterWriter { } } -fn line_num_max_digits(line: &codemap::LineInfo) -> usize { +fn line_num_max_digits(line: &LineInfo) -> usize { let mut max_line_num = line.line_index + 1; let mut digits = 0; while max_line_num > 0 { @@ -617,255 +633,3 @@ impl Write for Destination { } } } - - -#[cfg(test)] -mod test { - use errors::{Level, CodeSuggestion}; - use super::EmitterWriter; - use codemap::{mk_sp, CodeMap, Span, MultiSpan, BytePos, NO_EXPANSION}; - use std::sync::{Arc, Mutex}; - use std::io::{self, Write}; - use std::str::from_utf8; - use std::rc::Rc; - - struct Sink(Arc>>); - impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } - } - - /// Given a string like " ^~~~~~~~~~~~ ", produces a span - /// coverting that range. The idea is that the string has the same - /// length as the input, and we uncover the byte positions. Note - /// that this can span lines and so on. - fn span_from_selection(input: &str, selection: &str) -> Span { - assert_eq!(input.len(), selection.len()); - let left_index = selection.find('~').unwrap() as u32; - let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index); - Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } - } - - // Diagnostic doesn't align properly in span where line number increases by one digit - #[test] - fn test_hilight_suggestion_issue_11715() { - let data = Arc::new(Mutex::new(Vec::new())); - let cm = Rc::new(CodeMap::new()); - let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone()); - let content = "abcdefg - koksi - line3 - line4 - cinq - line6 - line7 - line8 - line9 - line10 - e-lä-vän - tolv - dreizehn - "; - let file = cm.new_filemap_and_lines("dummy.txt", None, content); - let start = file.lines.borrow()[10]; - let end = file.lines.borrow()[11]; - let sp = mk_sp(start, end); - let lvl = Level::Error; - println!("highlight_lines"); - ew.highlight_lines(&sp.into(), lvl).unwrap(); - println!("done"); - let vec = data.lock().unwrap().clone(); - let vec: &[u8] = &vec; - let str = from_utf8(vec).unwrap(); - println!("r#\"\n{}\"#", str); - assert_eq!(str, &r#" - --> dummy.txt:11:1 - |> -11 |> e-lä-vän - |> ^ -"#[1..]); - } - - #[test] - fn test_single_span_splice() { - // Test that a `MultiSpan` containing a single span splices a substition correctly - let cm = CodeMap::new(); - let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; - let selection = " \n ~~\n~~~\n~~~~~ \n \n"; - cm.new_filemap_and_lines("blork.rs", None, inputtext); - let sp = span_from_selection(inputtext, selection); - let msp: MultiSpan = sp.into(); - - // check that we are extracting the text we thought we were extracting - assert_eq!(&cm.span_to_snippet(sp).unwrap(), "BB\nCCC\nDDDDD"); - - let substitute = "ZZZZZZ".to_owned(); - let expected = "bbbbZZZZZZddddd"; - let suggest = CodeSuggestion { - msp: msp, - substitutes: vec![substitute], - }; - assert_eq!(suggest.splice_lines(&cm), expected); - } - - #[test] - fn test_multi_span_splice() { - // Test that a `MultiSpan` containing multiple spans splices a substition correctly - let cm = CodeMap::new(); - let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; - let selection1 = " \n \n \n \n ~ \n"; // intentionally out of order - let selection2 = " \n ~~\n~~~\n~~~~~ \n \n"; - cm.new_filemap_and_lines("blork.rs", None, inputtext); - let sp1 = span_from_selection(inputtext, selection1); - let sp2 = span_from_selection(inputtext, selection2); - let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]); - - let expected = "bbbbZZZZZZddddd\neXYZe"; - let suggest = CodeSuggestion { - msp: msp, - substitutes: vec!["ZZZZZZ".to_owned(), - "XYZ".to_owned()] - }; - - assert_eq!(suggest.splice_lines(&cm), expected); - } - - #[test] - fn test_multispan_highlight() { - let data = Arc::new(Mutex::new(Vec::new())); - let cm = Rc::new(CodeMap::new()); - let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone()); - - let inp = "_____aaaaaa____bbbbbb__cccccdd_"; - let sp1 = " ~~~~~~ "; - let sp2 = " ~~~~~~ "; - let sp3 = " ~~~~~ "; - let sp4 = " ~~~~ "; - let sp34 = " ~~~~~~~ "; - - let expect_start = &r#" - --> dummy.txt:1:6 - |> -1 |> _____aaaaaa____bbbbbb__cccccdd_ - |> ^^^^^^ ^^^^^^ ^^^^^^^ -"#[1..]; - - let span = |sp, expected| { - let sp = span_from_selection(inp, sp); - assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected); - sp - }; - cm.new_filemap_and_lines("dummy.txt", None, inp); - let sp1 = span(sp1, "aaaaaa"); - let sp2 = span(sp2, "bbbbbb"); - let sp3 = span(sp3, "ccccc"); - let sp4 = span(sp4, "ccdd"); - let sp34 = span(sp34, "cccccdd"); - - let spans = vec![sp1, sp2, sp3, sp4]; - - let test = |expected, highlight: &mut FnMut()| { - data.lock().unwrap().clear(); - highlight(); - let vec = data.lock().unwrap().clone(); - let actual = from_utf8(&vec[..]).unwrap(); - println!("actual=\n{}", actual); - assert_eq!(actual, expected); - }; - - let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]); - test(expect_start, &mut || { - diag.highlight_lines(&msp, Level::Error).unwrap(); - }); - test(expect_start, &mut || { - let msp = MultiSpan::from_spans(spans.clone()); - diag.highlight_lines(&msp, Level::Error).unwrap(); - }); - } - - #[test] - fn test_huge_multispan_highlight() { - let data = Arc::new(Mutex::new(Vec::new())); - let cm = Rc::new(CodeMap::new()); - let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone()); - - let inp = "aaaaa\n\ - aaaaa\n\ - aaaaa\n\ - bbbbb\n\ - ccccc\n\ - xxxxx\n\ - yyyyy\n\ - _____\n\ - ddd__eee_\n\ - elided\n\ - __f_gg"; - let file = cm.new_filemap_and_lines("dummy.txt", None, inp); - - let span = |lo, hi, (off_lo, off_hi)| { - let lines = file.lines.borrow(); - let (mut lo, mut hi): (BytePos, BytePos) = (lines[lo], lines[hi]); - lo.0 += off_lo; - hi.0 += off_hi; - mk_sp(lo, hi) - }; - let sp0 = span(4, 6, (0, 5)); - let sp1 = span(0, 6, (0, 5)); - let sp2 = span(8, 8, (0, 3)); - let sp3 = span(8, 8, (5, 8)); - let sp4 = span(10, 10, (2, 3)); - let sp5 = span(10, 10, (4, 6)); - - let expect0 = &r#" - --> dummy.txt:5:1 - |> -5 |> ccccc - |> ^ -... -9 |> ddd__eee_ - |> ^^^ ^^^ -10 |> elided -11 |> __f_gg - |> ^ ^^ -"#[1..]; - - let expect = &r#" - --> dummy.txt:1:1 - |> -1 |> aaaaa - |> ^ -... -9 |> ddd__eee_ - |> ^^^ ^^^ -10 |> elided -11 |> __f_gg - |> ^ ^^ -"#[1..]; - - macro_rules! test { - ($expected: expr, $highlight: expr) => ({ - data.lock().unwrap().clear(); - $highlight(); - let vec = data.lock().unwrap().clone(); - let actual = from_utf8(&vec[..]).unwrap(); - println!("actual:"); - println!("{}", actual); - println!("expected:"); - println!("{}", $expected); - assert_eq!(&actual[..], &$expected[..]); - }); - } - - let msp0 = MultiSpan::from_spans(vec![sp0, sp2, sp3, sp4, sp5]); - let msp = MultiSpan::from_spans(vec![sp1, sp2, sp3, sp4, sp5]); - - test!(expect0, || { - diag.highlight_lines(&msp0, Level::Error).unwrap(); - }); - test!(expect, || { - diag.highlight_lines(&msp, Level::Error).unwrap(); - }); - } -} diff --git a/syntex_syntax/src/errors/mod.rs b/syntex_errors/src/lib.rs similarity index 92% rename from syntex_syntax/src/errors/mod.rs rename to syntex_errors/src/lib.rs index f06672fe..18fc826f 100644 --- a/syntex_syntax/src/errors/mod.rs +++ b/syntex_errors/src/lib.rs @@ -8,24 +8,50 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use errors::emitter::ColorConfig; +#![crate_name = "rustc_errors"] +#![unstable(feature = "rustc_private", issue = "27812")] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] +#![cfg_attr(not(stage0), deny(warnings))] + +#![feature(custom_attribute)] +#![allow(unused_attributes)] +#![feature(rustc_private)] +#![feature(staged_api)] +#![feature(question_mark)] +#![feature(range_contains)] +#![feature(libc)] +#![feature(unicode)] + +extern crate serialize; +extern crate term; +#[macro_use] extern crate log; +#[macro_use] extern crate libc; +extern crate rustc_unicode; +extern crate serialize as rustc_serialize; // used by deriving +extern crate syntax_pos; + +pub use emitter::ColorConfig; use self::Level::*; use self::RenderSpan::*; -use codemap::{self, CodeMap, MultiSpan, NO_EXPANSION, Span}; -use diagnostics; -use errors::emitter::{Emitter, EmitterWriter}; +use emitter::{Emitter, EmitterWriter}; use std::cell::{RefCell, Cell}; use std::{error, fmt}; use std::rc::Rc; use std::thread::panicking; -use term; pub mod emitter; -pub mod json; pub mod snippet; +pub mod registry; + +use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION }; +use syntax_pos::{MacroBacktrace}; #[derive(Clone)] pub enum RenderSpan { @@ -43,8 +69,16 @@ pub enum RenderSpan { #[derive(Clone)] pub struct CodeSuggestion { - msp: MultiSpan, - substitutes: Vec, + pub msp: MultiSpan, + pub substitutes: Vec, +} + +pub trait CodeMapper { + fn lookup_char_pos(&self, pos: BytePos) -> Loc; + fn span_to_lines(&self, sp: Span) -> FileLinesResult; + fn span_to_string(&self, sp: Span) -> String; + fn span_to_filename(&self, sp: Span) -> FileName; + fn macro_backtrace(&self, span: Span) -> Vec; } impl RenderSpan { @@ -59,8 +93,8 @@ impl RenderSpan { impl CodeSuggestion { /// Returns the assembled code suggestion. - pub fn splice_lines(&self, cm: &CodeMap) -> String { - use codemap::{CharPos, Loc, Pos}; + pub fn splice_lines(&self, cm: &CodeMapper) -> String { + use syntax_pos::{CharPos, Loc, Pos}; fn push_trailing(buf: &mut String, line_opt: Option<&str>, lo: &Loc, hi_opt: Option<&Loc>) { @@ -181,20 +215,20 @@ impl error::Error for ExplicitBug { #[derive(Clone)] pub struct DiagnosticBuilder<'a> { handler: &'a Handler, - level: Level, - message: String, - code: Option, - span: MultiSpan, - children: Vec, + pub level: Level, + pub message: String, + pub code: Option, + pub span: MultiSpan, + pub children: Vec, } /// For example a note attached to an error. #[derive(Clone)] -struct SubDiagnostic { - level: Level, - message: String, - span: MultiSpan, - render_span: Option, +pub struct SubDiagnostic { + pub level: Level, + pub message: String, + pub span: MultiSpan, + pub render_span: Option, } impl<'a> DiagnosticBuilder<'a> { @@ -386,12 +420,13 @@ pub struct Handler { impl Handler { pub fn with_tty_emitter(color_config: ColorConfig, - registry: Option, + registry: Option, can_emit_warnings: bool, treat_err_as_bug: bool, - cm: Rc) + cm: Rc) -> Handler { - let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm)); + let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm, + snippet::FormatMode::EnvironmentSelected)); Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter) } @@ -662,7 +697,7 @@ impl fmt::Display for Level { } impl Level { - fn color(self) -> term::color::Color { + pub fn color(self) -> term::color::Color { match self { Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED, Warning => term::color::YELLOW, @@ -672,7 +707,7 @@ impl Level { } } - fn to_str(self) -> &'static str { + pub fn to_str(self) -> &'static str { match self { Bug => "error: internal compiler error", Fatal | PhaseFatal | Error => "error", diff --git a/syntex_syntax/src/diagnostics/registry.rs b/syntex_errors/src/registry.rs similarity index 100% rename from syntex_syntax/src/diagnostics/registry.rs rename to syntex_errors/src/registry.rs diff --git a/syntex_syntax/src/errors/snippet/mod.rs b/syntex_errors/src/snippet.rs similarity index 95% rename from syntex_syntax/src/errors/snippet/mod.rs rename to syntex_errors/src/snippet.rs index 2a43a14d..33f40ffc 100644 --- a/syntex_syntax/src/errors/snippet/mod.rs +++ b/syntex_errors/src/snippet.rs @@ -10,18 +10,25 @@ // Code for annotating snippets. -use codemap::{CharPos, CodeMap, FileMap, LineInfo, Span}; -use errors::check_old_skool; +use syntax_pos::{Span, FileMap, CharPos, LineInfo}; +use check_old_skool; +use CodeMapper; use std::cmp; use std::rc::Rc; use std::mem; -mod test; +#[derive(Clone)] +pub enum FormatMode { + NewErrorFormat, + OriginalErrorFormat, + EnvironmentSelected +} #[derive(Clone)] pub struct SnippetData { - codemap: Rc, + codemap: Rc, files: Vec, + format_mode: FormatMode, } #[derive(Clone)] @@ -36,6 +43,10 @@ pub struct FileInfo { primary_span: Option, lines: Vec, + + /// The type of error format to render. We keep it here so that + /// it's easy to configure for both tests and regular usage + format_mode: FormatMode, } #[derive(Clone, Debug)] @@ -111,8 +122,9 @@ pub enum RenderedLineKind { } impl SnippetData { - pub fn new(codemap: Rc, - primary_span: Option) // (*) + pub fn new(codemap: Rc, + primary_span: Option, + format_mode: FormatMode) // (*) -> Self { // (*) The primary span indicates the file that must appear // first, and which will have a line number etc in its @@ -126,7 +138,8 @@ impl SnippetData { let mut data = SnippetData { codemap: codemap.clone(), - files: vec![] + files: vec![], + format_mode: format_mode.clone() }; if let Some(primary_span) = primary_span { let lo = codemap.lookup_char_pos(primary_span.lo); @@ -135,6 +148,7 @@ impl SnippetData { file: lo.file, primary_span: Some(primary_span), lines: vec![], + format_mode: format_mode.clone(), }); } data @@ -167,6 +181,7 @@ impl SnippetData { file: file_map.clone(), lines: vec![], primary_span: None, + format_mode: self.format_mode.clone() }); self.files.last_mut().unwrap() } @@ -178,7 +193,7 @@ impl SnippetData { self.files.iter() .flat_map(|f| f.render_file_lines(&self.codemap)) .collect(); - prepend_prefixes(&mut rendered_lines); + prepend_prefixes(&mut rendered_lines, &self.format_mode); trim_lines(&mut rendered_lines); rendered_lines } @@ -454,8 +469,12 @@ impl FileInfo { return line_index - first_line_index; } - fn render_file_lines(&self, codemap: &Rc) -> Vec { - let old_school = check_old_skool(); + fn render_file_lines(&self, codemap: &Rc) -> Vec { + let old_school = match self.format_mode { + FormatMode::OriginalErrorFormat => true, + FormatMode::NewErrorFormat => false, + FormatMode::EnvironmentSelected => check_old_skool() + }; // As a first step, we elide any instance of more than one // continuous unannotated line. @@ -591,7 +610,12 @@ impl FileInfo { } fn render_line(&self, line: &Line) -> Vec { - let old_school = check_old_skool(); + let old_school = match self.format_mode { + FormatMode::OriginalErrorFormat => true, + FormatMode::NewErrorFormat => false, + FormatMode::EnvironmentSelected => check_old_skool() + }; + let source_string = self.file.get_line(line.line_index) .unwrap_or(""); let source_kind = RenderedLineKind::SourceText { @@ -776,8 +800,12 @@ impl FileInfo { } } -fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { - let old_school = check_old_skool(); +fn prepend_prefixes(rendered_lines: &mut [RenderedLine], format_mode: &FormatMode) { + let old_school = match *format_mode { + FormatMode::OriginalErrorFormat => true, + FormatMode::NewErrorFormat => false, + FormatMode::EnvironmentSelected => check_old_skool() + }; if old_school { return; } diff --git a/syntex_syntax/src/Cargo.toml b/syntex_syntax/src/Cargo.toml index 964f2dcb..8b61e1b0 100644 --- a/syntex_syntax/src/Cargo.toml +++ b/syntex_syntax/src/Cargo.toml @@ -12,3 +12,5 @@ crate-type = ["dylib"] serialize = { path = "../libserialize" } log = { path = "../liblog" } rustc_bitflags = { path = "../librustc_bitflags" } +syntax_pos = { path = "../libsyntax_pos" } +rustc_errors = { path = "../librustc_errors" } diff --git a/syntex_syntax/src/ast.rs b/syntex_syntax/src/ast.rs index 8537fcc2..cc033cec 100644 --- a/syntex_syntax/src/ast.rs +++ b/syntex_syntax/src/ast.rs @@ -14,22 +14,18 @@ pub use self::TyParamBound::*; pub use self::UnsafeSource::*; pub use self::ViewPath_::*; pub use self::PathParameters::*; +pub use util::ThinVec; -use attr::{ThinAttributes, HasAttrs}; -use codemap::{mk_sp, respan, Span, Spanned, DUMMY_SP, ExpnId}; +use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId}; +use codemap::{respan, Spanned}; use abi::Abi; -use errors; -use ext::base; -use ext::tt::macro_parser; use parse::token::{self, keywords, InternedString}; -use parse::lexer; -use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use print::pprust; use ptr::P; +use tokenstream::{TokenTree}; use std::fmt; use std::rc::Rc; -use std::borrow::Cow; use std::hash::{Hash, Hasher}; use serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -171,16 +167,19 @@ impl fmt::Debug for Lifetime { } } -/// A lifetime definition, eg `'a: 'b+'c+'d` +/// A lifetime definition, e.g. `'a: 'b+'c+'d` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct LifetimeDef { pub lifetime: Lifetime, pub bounds: Vec } -/// A "Path" is essentially Rust's notion of a name; for instance: -/// std::cmp::PartialEq . It's represented as a sequence of identifiers, +/// A "Path" is essentially Rust's notion of a name. +/// +/// It's represented as a sequence of identifiers, /// along with a bunch of supporting information. +/// +/// E.g. `std::cmp::PartialEq` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Path { pub span: Span, @@ -220,8 +219,9 @@ impl Path { } } -/// A segment of a path: an identifier, an optional lifetime, and a set of -/// types. +/// A segment of a path: an identifier, an optional lifetime, and a set of types. +/// +/// E.g. `std`, `String` or `Box` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct PathSegment { /// The identifier portion of this path segment. @@ -235,6 +235,9 @@ pub struct PathSegment { pub parameters: PathParameters, } +/// Parameters of a path segment. +/// +/// E.g. `` as in `Foo` or `(A, B)` as in `Foo(A, B)` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum PathParameters { /// The `<'a, A,B,C>` in `foo::bar::baz::<'a, A,B,C>` @@ -322,7 +325,8 @@ pub struct AngleBracketedParameterData { /// The type parameters for this path segment, if present. pub types: P<[P]>, /// Bindings (equality constraints) on associated types, if present. - /// e.g., `Foo`. + /// + /// E.g., `Foo`. pub bindings: P<[TypeBinding]>, } @@ -357,15 +361,6 @@ pub const CRATE_NODE_ID: NodeId = 0; /// small, positive ids. pub const DUMMY_NODE_ID: NodeId = !0; -pub trait NodeIdAssigner { - fn next_node_id(&self) -> NodeId; - fn peek_node_id(&self) -> NodeId; - - fn diagnostic(&self) -> &errors::Handler { - panic!("this ID assigner cannot emit diagnostics") - } -} - /// The AST represents all type param bounds as types. /// typeck::collect::compute_bounds matches these against /// the "special" built-in traits (see middle::lang_items) and @@ -447,7 +442,9 @@ pub enum WherePredicate { EqPredicate(WhereEqPredicate), } -/// A type bound, e.g. `for<'c> Foo: Send+Clone+'c` +/// A type bound. +/// +/// E.g. `for<'c> Foo: Send+Clone+'c` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct WhereBoundPredicate { pub span: Span, @@ -459,7 +456,9 @@ pub struct WhereBoundPredicate { pub bounds: TyParamBounds, } -/// A lifetime predicate, e.g. `'a: 'b+'c` +/// A lifetime predicate. +/// +/// E.g. `'a: 'b+'c` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct WhereRegionPredicate { pub span: Span, @@ -467,7 +466,9 @@ pub struct WhereRegionPredicate { pub bounds: Vec, } -/// An equality predicate (unsupported), e.g. `T=int` +/// An equality predicate (unsupported). +/// +/// E.g. `T=int` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct WhereEqPredicate { pub id: NodeId, @@ -489,12 +490,27 @@ pub struct Crate { pub exported_macros: Vec, } +/// A spanned compile-time attribute item. +/// +/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]` pub type MetaItem = Spanned; +/// A compile-time attribute item. +/// +/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]` #[derive(Clone, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum MetaItemKind { + /// Word meta item. + /// + /// E.g. `test` as in `#[test]` Word(InternedString), + /// List meta item. + /// + /// E.g. `derive(..)` as in `#[derive(..)]` List(InternedString, Vec>), + /// Name value meta item. + /// + /// E.g. `feature = "foo"` as in `#[feature = "foo"]` NameValue(InternedString, Lit), } @@ -524,13 +540,13 @@ impl PartialEq for MetaItemKind { } } +/// A Block (`{ .. }`). +/// +/// E.g. `{ .. }` as in `fn foo() { .. }` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Block { /// Statements in a block pub stmts: Vec, - /// An expression at the end of the block - /// without a semicolon, if any - pub expr: Option>, pub id: NodeId, /// Distinguishes between `unsafe { ... }` and `{ ... }` pub rules: BlockCheckMode, @@ -579,7 +595,6 @@ impl Pat { PatKind::Range(_, _) | PatKind::Ident(_, _, _) | PatKind::Path(..) | - PatKind::QPath(_, _) | PatKind::Mac(_) => { true } @@ -627,15 +642,11 @@ pub enum PatKind { /// 0 <= position <= subpats.len() TupleStruct(Path, Vec>, Option), - /// A path pattern. - /// Such pattern can be resolved to a unit struct/variant or a constant. - Path(Path), - - /// An associated const named using the qualified path `::CONST` or - /// `::CONST`. Associated consts from inherent impls can be - /// referred to as simply `T::CONST`, in which case they will end up as - /// PatKind::Path, and the resolver will have to sort that out. - QPath(QSelf, Path), + /// A possibly qualified path pattern. + /// Unquailfied path patterns `A::B::C` can legally refer to variants, structs, constants + /// or associated constants. Quailfied path patterns `::B::C`/`::B::C` can + /// only legally refer to associated constants. + Path(Option, Path), /// A tuple pattern `(a, b)`. /// If the `..` pattern fragment is present, then `Option` denotes its position. @@ -786,45 +797,34 @@ impl UnOp { } /// A statement -pub type Stmt = Spanned; +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] +pub struct Stmt { + pub id: NodeId, + pub node: StmtKind, + pub span: Span, +} impl fmt::Debug for Stmt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "stmt({}: {})", - self.node.id() - .map_or(Cow::Borrowed(""),|id|Cow::Owned(id.to_string())), - pprust::stmt_to_string(self)) + write!(f, "stmt({}: {})", self.id.to_string(), pprust::stmt_to_string(self)) } } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub enum StmtKind { - /// Could be an item or a local (let) binding: - Decl(P, NodeId), + /// A local (let) binding. + Local(P), - /// Expr without trailing semi-colon (must have unit type): - Expr(P, NodeId), + /// An item definition. + Item(P), - /// Expr with trailing semi-colon (may have any type): - Semi(P, NodeId), + /// Expr without trailing semi-colon. + Expr(P), - Mac(P, MacStmtStyle, ThinAttributes), -} + Semi(P), -impl StmtKind { - pub fn id(&self) -> Option { - match *self { - StmtKind::Decl(_, id) => Some(id), - StmtKind::Expr(_, id) => Some(id), - StmtKind::Semi(_, id) => Some(id), - StmtKind::Mac(..) => None, - } - } - - pub fn attrs(&self) -> &[Attribute] { - HasAttrs::attrs(self) - } + Mac(P<(Mac, MacStmtStyle, ThinVec)>), } #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -851,32 +851,19 @@ pub struct Local { pub init: Option>, pub id: NodeId, pub span: Span, - pub attrs: ThinAttributes, -} - -impl Local { - pub fn attrs(&self) -> &[Attribute] { - HasAttrs::attrs(self) - } + pub attrs: ThinVec, } -pub type Decl = Spanned; - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum DeclKind { - /// A local (let) binding: - Local(P), - /// An item binding: - Item(P), -} - -impl Decl { - pub fn attrs(&self) -> &[Attribute] { - HasAttrs::attrs(self) - } -} - -/// represents one arm of a 'match' +/// An arm of a 'match'. +/// +/// E.g. `0...10 => { println!("match!") }` as in +/// +/// ```rust,ignore +/// match n { +/// 0...10 => { println!("match!") }, +/// // .. +/// } +/// ``` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Arm { pub attrs: Vec, @@ -912,13 +899,7 @@ pub struct Expr { pub id: NodeId, pub node: ExprKind, pub span: Span, - pub attrs: ThinAttributes -} - -impl Expr { - pub fn attrs(&self) -> &[Attribute] { - HasAttrs::attrs(self) - } + pub attrs: ThinVec } impl fmt::Debug for Expr { @@ -1033,7 +1014,7 @@ pub enum ExprKind { /// parameters, e.g. foo::bar::. /// /// Optionally "qualified", - /// e.g. ` as SomeTrait>::SomeType`. + /// E.g. ` as SomeTrait>::SomeType`. Path(Option, Path), /// A referencing operation (`&a` or `&mut a`) @@ -1041,7 +1022,7 @@ pub enum ExprKind { /// A `break`, with an optional label to break Break(Option), /// A `continue`, with an optional label - Again(Option), + Continue(Option), /// A `return`, with an optional value to be returned Ret(Option>), @@ -1075,7 +1056,7 @@ pub enum ExprKind { /// separately. `position` represents the index of the associated /// item qualified with this Self type. /// -/// ```ignore +/// ```rust,ignore /// as a::b::Trait>::AssociatedItem /// ^~~~~ ~~~~~~~~~~~~~~^ /// ty position = 3 @@ -1097,193 +1078,6 @@ pub enum CaptureBy { Ref, } -/// A delimited sequence of token trees -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct Delimited { - /// The type of delimiter - pub delim: token::DelimToken, - /// The span covering the opening delimiter - pub open_span: Span, - /// The delimited sequence of token trees - pub tts: Vec, - /// The span covering the closing delimiter - pub close_span: Span, -} - -impl Delimited { - /// Returns the opening delimiter as a token. - pub fn open_token(&self) -> token::Token { - token::OpenDelim(self.delim) - } - - /// Returns the closing delimiter as a token. - pub fn close_token(&self) -> token::Token { - token::CloseDelim(self.delim) - } - - /// Returns the opening delimiter as a token tree. - pub fn open_tt(&self) -> TokenTree { - TokenTree::Token(self.open_span, self.open_token()) - } - - /// Returns the closing delimiter as a token tree. - pub fn close_tt(&self) -> TokenTree { - TokenTree::Token(self.close_span, self.close_token()) - } -} - -/// A sequence of token trees -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct SequenceRepetition { - /// The sequence of token trees - pub tts: Vec, - /// The optional separator - pub separator: Option, - /// Whether the sequence can be repeated zero (*), or one or more times (+) - pub op: KleeneOp, - /// The number of `MatchNt`s that appear in the sequence (and subsequences) - pub num_captures: usize, -} - -/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) -/// for token sequences. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum KleeneOp { - ZeroOrMore, - OneOrMore, -} - -/// When the main rust parser encounters a syntax-extension invocation, it -/// parses the arguments to the invocation as a token-tree. This is a very -/// loose structure, such that all sorts of different AST-fragments can -/// be passed to syntax extensions using a uniform type. -/// -/// If the syntax extension is an MBE macro, it will attempt to match its -/// LHS token tree against the provided token tree, and if it finds a -/// match, will transcribe the RHS token tree, splicing in any captured -/// macro_parser::matched_nonterminals into the `SubstNt`s it finds. -/// -/// The RHS of an MBE macro is the only place `SubstNt`s are substituted. -/// Nothing special happens to misnamed or misplaced `SubstNt`s. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum TokenTree { - /// A single token - Token(Span, token::Token), - /// A delimited sequence of token trees - Delimited(Span, Rc), - - // This only makes sense in MBE macros. - - /// A kleene-style repetition sequence with a span - // FIXME(eddyb) #12938 Use DST. - Sequence(Span, Rc), -} - -impl TokenTree { - pub fn len(&self) -> usize { - match *self { - TokenTree::Token(_, token::DocComment(name)) => { - match doc_comment_style(&name.as_str()) { - AttrStyle::Outer => 2, - AttrStyle::Inner => 3 - } - } - TokenTree::Token(_, token::SpecialVarNt(..)) => 2, - TokenTree::Token(_, token::MatchNt(..)) => 3, - TokenTree::Delimited(_, ref delimed) => { - delimed.tts.len() + 2 - } - TokenTree::Sequence(_, ref seq) => { - seq.tts.len() - } - TokenTree::Token(..) => 0 - } - } - - pub fn get_tt(&self, index: usize) -> TokenTree { - match (self, index) { - (&TokenTree::Token(sp, token::DocComment(_)), 0) => { - TokenTree::Token(sp, token::Pound) - } - (&TokenTree::Token(sp, token::DocComment(name)), 1) - if doc_comment_style(&name.as_str()) == AttrStyle::Inner => { - TokenTree::Token(sp, token::Not) - } - (&TokenTree::Token(sp, token::DocComment(name)), _) => { - let stripped = strip_doc_comment_decoration(&name.as_str()); - - // Searches for the occurrences of `"#*` and returns the minimum number of `#`s - // required to wrap the text. - let num_of_hashes = stripped.chars().scan(0, |cnt, x| { - *cnt = if x == '"' { - 1 - } else if *cnt != 0 && x == '#' { - *cnt + 1 - } else { - 0 - }; - Some(*cnt) - }).max().unwrap_or(0); - - TokenTree::Delimited(sp, Rc::new(Delimited { - delim: token::Bracket, - open_span: sp, - tts: vec![TokenTree::Token(sp, token::Ident(token::str_to_ident("doc"))), - TokenTree::Token(sp, token::Eq), - TokenTree::Token(sp, token::Literal( - token::StrRaw(token::intern(&stripped), num_of_hashes), None))], - close_span: sp, - })) - } - (&TokenTree::Delimited(_, ref delimed), _) => { - if index == 0 { - return delimed.open_tt(); - } - if index == delimed.tts.len() + 1 { - return delimed.close_tt(); - } - delimed.tts[index - 1].clone() - } - (&TokenTree::Token(sp, token::SpecialVarNt(var)), _) => { - let v = [TokenTree::Token(sp, token::Dollar), - TokenTree::Token(sp, token::Ident(token::str_to_ident(var.as_str())))]; - v[index].clone() - } - (&TokenTree::Token(sp, token::MatchNt(name, kind)), _) => { - let v = [TokenTree::Token(sp, token::SubstNt(name)), - TokenTree::Token(sp, token::Colon), - TokenTree::Token(sp, token::Ident(kind))]; - v[index].clone() - } - (&TokenTree::Sequence(_, ref seq), _) => { - seq.tts[index].clone() - } - _ => panic!("Cannot expand a token tree") - } - } - - /// Returns the `Span` corresponding to this token tree. - pub fn get_span(&self) -> Span { - match *self { - TokenTree::Token(span, _) => span, - TokenTree::Delimited(span, _) => span, - TokenTree::Sequence(span, _) => span, - } - } - - /// Use this token tree as a matcher to parse given tts. - pub fn parse(cx: &base::ExtCtxt, mtch: &[TokenTree], tts: &[TokenTree]) - -> macro_parser::NamedParseResult { - // `None` is because we're not interpolating - let arg_rdr = lexer::new_tt_reader_with_doc_flag(&cx.parse_sess().span_diagnostic, - None, - None, - tts.iter().cloned().collect(), - true); - macro_parser::parse(cx.parse_sess(), cx.cfg(), arg_rdr, mtch) - } -} - pub type Mac = Spanned; /// Represents a macro invocation. The Path indicates which macro @@ -1296,7 +1090,6 @@ pub type Mac = Spanned; pub struct Mac_ { pub path: Path, pub tts: Vec, - pub ctxt: SyntaxContext, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -1319,6 +1112,9 @@ pub enum LitIntType { Unsuffixed, } +/// Literal kind. +/// +/// E.g. `"foo"`, `42`, `12.34` or `bool` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum LitKind { /// A string literal (`"foo"`) @@ -1386,6 +1182,7 @@ pub enum TraitItemKind { Const(P, Option>), Method(MethodSig, Option>), Type(TyParamBounds, Option>), + Macro(Mac), } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -1586,8 +1383,8 @@ pub struct BareFnTy { pub decl: P } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] /// The different kinds of types recognized by the compiler +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum TyKind { Vec(P), /// A fixed length array (`[T; n]`) @@ -1622,12 +1419,18 @@ pub enum TyKind { Mac(Mac), } +/// Inline assembly dialect. +/// +/// E.g. `"intel"` as in `asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum AsmDialect { Att, Intel, } +/// Inline assembly. +/// +/// E.g. `"={eax}"(result)` as in `asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct InlineAsmOutput { pub constraint: InternedString, @@ -1636,6 +1439,9 @@ pub struct InlineAsmOutput { pub is_indirect: bool, } +/// Inline assembly. +/// +/// E.g. `asm!("NOP");` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct InlineAsm { pub asm: InternedString, @@ -1649,7 +1455,9 @@ pub struct InlineAsm { pub expn_id: ExpnId, } -/// represents an argument in a function header +/// An argument in a function header. +/// +/// E.g. `bar: usize` as in `fn foo(bar: usize)` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Arg { pub ty: P, @@ -1658,6 +1466,8 @@ pub struct Arg { } /// Alternative representation for `Arg`s describing `self` parameter of methods. +/// +/// E.g. `&mut self` as in `fn foo(&mut self)` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum SelfKind { /// `self`, `mut self` @@ -1724,7 +1534,9 @@ impl Arg { } } -/// Represents the header (not the body) of a function declaration +/// Header (not the body) of a function declaration. +/// +/// E.g. `fn foo(bar: baz)` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct FnDecl { pub inputs: Vec, @@ -1811,6 +1623,9 @@ impl FunctionRetTy { } } +/// Module declaration. +/// +/// E.g. `mod foo;` or `mod foo { .. }` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Mod { /// A span from the first token past `{` to the last token until `}`. @@ -1820,6 +1635,9 @@ pub struct Mod { pub items: Vec>, } +/// Foreign module declaration. +/// +/// E.g. `extern { .. }` or `extern C { .. }` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ForeignMod { pub abi: Abi, @@ -1836,7 +1654,7 @@ pub struct Variant_ { pub name: Ident, pub attrs: Vec, pub data: VariantData, - /// Explicit discriminant, eg `Foo = 1` + /// Explicit discriminant, e.g. `Foo = 1` pub disr_expr: Option>, } @@ -1846,12 +1664,12 @@ pub type Variant = Spanned; pub enum PathListItemKind { Ident { name: Ident, - /// renamed in list, eg `use foo::{bar as baz};` + /// renamed in list, e.g. `use foo::{bar as baz};` rename: Option, id: NodeId }, Mod { - /// renamed in list, eg `use foo::{self as baz};` + /// renamed in list, e.g. `use foo::{self as baz};` rename: Option, id: NodeId } @@ -1964,6 +1782,9 @@ pub enum Visibility { Inherited, } +/// Field of a struct. +/// +/// E.g. `bar: usize` as in `struct Foo { bar: usize }` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct StructField { pub span: Span, @@ -1987,8 +1808,17 @@ pub struct StructField { /// Id of the whole struct lives in `Item`. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum VariantData { + /// Struct variant. + /// + /// E.g. `Bar { .. }` as in `enum Foo { Bar { .. } }` Struct(Vec, NodeId), + /// Tuple variant. + /// + /// E.g. `Bar(..)` as in `enum Foo { Bar(..) }` Tuple(Vec, NodeId), + /// Unit variant. + /// + /// E.g. `Bar = ..` as in `enum Foo { Bar = .. }` Unit(NodeId), } @@ -2032,52 +1862,68 @@ pub struct Item { pub span: Span, } -impl Item { - pub fn attrs(&self) -> &[Attribute] { - &self.attrs - } -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum ItemKind { - /// An`extern crate` item, with optional original crate name, + /// An`extern crate` item, with optional original crate name. /// - /// e.g. `extern crate foo` or `extern crate foo_bar as foo` + /// E.g. `extern crate foo` or `extern crate foo_bar as foo` ExternCrate(Option), - /// A `use` or `pub use` item + /// A use declaration (`use` or `pub use`) item. + /// + /// E.g. `use foo;`, `use foo::bar;` or `use foo::bar as FooBar;` Use(P), - - /// A `static` item + /// A static item (`static` or `pub static`). + /// + /// E.g. `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";` Static(P, Mutability, P), - /// A `const` item + /// A constant item (`const` or `pub const`). + /// + /// E.g. `const FOO: i32 = 42;` Const(P, P), - /// A function declaration + /// A function declaration (`fn` or `pub fn`). + /// + /// E.g. `fn foo(bar: usize) -> usize { .. }` Fn(P, Unsafety, Constness, Abi, Generics, P), - /// A module + /// A module declaration (`mod` or `pub mod`). + /// + /// E.g. `mod foo;` or `mod foo { .. }` Mod(Mod), - /// An external module + /// An external module (`extern` or `pub extern`). + /// + /// E.g. `extern {}` or `extern "C" {}` ForeignMod(ForeignMod), - /// A type alias, e.g. `type Foo = Bar` + /// A type alias (`type` or `pub type`). + /// + /// E.g. `type Foo = Bar;` Ty(P, Generics), - /// An enum definition, e.g. `enum Foo {C, D}` + /// An enum definition (`enum` or `pub enum`). + /// + /// E.g. `enum Foo { C, D }` Enum(EnumDef, Generics), - /// A struct definition, e.g. `struct Foo {x: A}` + /// A struct definition (`struct` or `pub struct`). + /// + /// E.g. `struct Foo { x: A }` Struct(VariantData, Generics), - /// Represents a Trait Declaration + /// A Trait declaration (`trait` or `pub trait`). + /// + /// E.g. `trait Foo { .. }` or `trait Foo { .. }` Trait(Unsafety, Generics, TyParamBounds, Vec), - - // Default trait implementations + // Default trait implementation. /// - // `impl Trait for .. {}` + /// E.g. `impl Trait for .. {}` or `impl Trait for .. {}` DefaultImpl(Unsafety, TraitRef), - /// An implementation, eg `impl Trait for Foo { .. }` + /// An implementation. + /// + /// E.g. `impl Foo { .. }` or `impl Trait for Foo { .. }` Impl(Unsafety, ImplPolarity, Generics, Option, // (optional) trait this impl implements P, // self Vec), - /// A macro invocation (which includes macro definition) + /// A macro invocation (which includes macro definition). + /// + /// E.g. `macro_rules! foo { .. }` or `foo!(..)` Mac(Mac), } diff --git a/syntex_syntax/src/attr.rs b/syntex_syntax/src/attr.rs index e36e1580..3c88fb8f 100644 --- a/syntex_syntax/src/attr.rs +++ b/syntex_syntax/src/attr.rs @@ -16,16 +16,16 @@ pub use self::IntType::*; use ast; use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaItemKind}; -use ast::{Stmt, StmtKind, DeclKind}; -use ast::{Expr, Item, Local, Decl}; -use codemap::{Span, Spanned, spanned, dummy_spanned}; -use codemap::BytePos; +use ast::{Expr, Item, Local, Stmt, StmtKind}; +use codemap::{spanned, dummy_spanned, Spanned}; +use syntax_pos::{Span, BytePos}; use errors::Handler; use feature_gate::{Features, GatedCfg}; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use parse::token::InternedString; use parse::{ParseSess, token}; use ptr::P; +use util::ThinVec; use std::cell::{RefCell, Cell}; use std::collections::HashSet; @@ -803,100 +803,11 @@ impl IntType { } } -/// A list of attributes, behind a optional box as -/// a space optimization. -pub type ThinAttributes = Option>>; - -pub trait ThinAttributesExt { - fn map_thin_attrs(self, f: F) -> Self - where F: FnOnce(Vec) -> Vec; - fn prepend(mut self, attrs: Self) -> Self; - fn append(mut self, attrs: Self) -> Self; - fn update(&mut self, f: F) - where Self: Sized, - F: FnOnce(Self) -> Self; - fn as_attr_slice(&self) -> &[Attribute]; - fn into_attr_vec(self) -> Vec; -} - -impl ThinAttributesExt for ThinAttributes { - fn map_thin_attrs(self, f: F) -> Self - where F: FnOnce(Vec) -> Vec - { - f(self.map(|b| *b).unwrap_or(Vec::new())).into_thin_attrs() - } - - fn prepend(self, attrs: ThinAttributes) -> Self { - attrs.map_thin_attrs(|mut attrs| { - attrs.extend(self.into_attr_vec()); - attrs - }) - } - - fn append(self, attrs: ThinAttributes) -> Self { - self.map_thin_attrs(|mut self_| { - self_.extend(attrs.into_attr_vec()); - self_ - }) - } - - fn update(&mut self, f: F) - where Self: Sized, - F: FnOnce(ThinAttributes) -> ThinAttributes - { - let self_ = f(self.take()); - *self = self_; - } - - fn as_attr_slice(&self) -> &[Attribute] { - match *self { - Some(ref b) => b, - None => &[], - } - } - - fn into_attr_vec(self) -> Vec { - match self { - Some(b) => *b, - None => Vec::new(), - } - } -} - -pub trait AttributesExt { - fn into_thin_attrs(self) -> ThinAttributes; -} - -impl AttributesExt for Vec { - fn into_thin_attrs(self) -> ThinAttributes { - if self.len() == 0 { - None - } else { - Some(Box::new(self)) - } - } -} - pub trait HasAttrs: Sized { fn attrs(&self) -> &[ast::Attribute]; fn map_attrs) -> Vec>(self, f: F) -> Self; } -/// A cheap way to add Attributes to an AST node. -pub trait WithAttrs { - // FIXME: Could be extended to anything IntoIter - fn with_attrs(self, attrs: ThinAttributes) -> Self; -} - -impl WithAttrs for T { - fn with_attrs(self, attrs: ThinAttributes) -> Self { - self.map_attrs(|mut orig_attrs| { - orig_attrs.extend(attrs.into_attr_vec()); - orig_attrs - }) - } -} - impl HasAttrs for Vec { fn attrs(&self) -> &[Attribute] { &self @@ -906,12 +817,12 @@ impl HasAttrs for Vec { } } -impl HasAttrs for ThinAttributes { +impl HasAttrs for ThinVec { fn attrs(&self) -> &[Attribute] { - self.as_attr_slice() + &self } fn map_attrs) -> Vec>(self, f: F) -> Self { - self.map_thin_attrs(f) + f(self.into()).into() } } @@ -924,38 +835,28 @@ impl HasAttrs for P { } } -impl HasAttrs for DeclKind { - fn attrs(&self) -> &[Attribute] { - match *self { - DeclKind::Local(ref local) => local.attrs(), - DeclKind::Item(ref item) => item.attrs(), - } - } - - fn map_attrs) -> Vec>(self, f: F) -> Self { - match self { - DeclKind::Local(local) => DeclKind::Local(local.map_attrs(f)), - DeclKind::Item(item) => DeclKind::Item(item.map_attrs(f)), - } - } -} - impl HasAttrs for StmtKind { fn attrs(&self) -> &[Attribute] { match *self { - StmtKind::Decl(ref decl, _) => decl.attrs(), - StmtKind::Expr(ref expr, _) | StmtKind::Semi(ref expr, _) => expr.attrs(), - StmtKind::Mac(_, _, ref attrs) => attrs.attrs(), + StmtKind::Local(ref local) => local.attrs(), + StmtKind::Item(..) => &[], + StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(), + StmtKind::Mac(ref mac) => { + let (_, _, ref attrs) = **mac; + attrs.attrs() + } } } fn map_attrs) -> Vec>(self, f: F) -> Self { match self { - StmtKind::Decl(decl, id) => StmtKind::Decl(decl.map_attrs(f), id), - StmtKind::Expr(expr, id) => StmtKind::Expr(expr.map_attrs(f), id), - StmtKind::Semi(expr, id) => StmtKind::Semi(expr.map_attrs(f), id), - StmtKind::Mac(mac, style, attrs) => - StmtKind::Mac(mac, style, attrs.map_attrs(f)), + StmtKind::Local(local) => StmtKind::Local(local.map_attrs(f)), + StmtKind::Item(..) => self, + StmtKind::Expr(expr) => StmtKind::Expr(expr.map_attrs(f)), + StmtKind::Semi(expr) => StmtKind::Semi(expr.map_attrs(f)), + StmtKind::Mac(mac) => StmtKind::Mac(mac.map(|(mac, style, attrs)| { + (mac, style, attrs.map_attrs(f)) + })), } } } @@ -982,4 +883,4 @@ derive_has_attrs_from_field! { Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm } -derive_has_attrs_from_field! { Decl: .node, Stmt: .node, ast::Variant: .node.attrs } +derive_has_attrs_from_field! { Stmt: .node, ast::Variant: .node.attrs } diff --git a/syntex_syntax/src/codemap.rs b/syntex_syntax/src/codemap.rs index 5e1335b4..743f96d7 100644 --- a/syntex_syntax/src/codemap.rs +++ b/syntex_syntax/src/codemap.rs @@ -19,269 +19,18 @@ pub use self::ExpnFormat::*; -use std::cell::{Cell, RefCell}; -use std::ops::{Add, Sub}; +use std::cell::RefCell; use std::path::{Path,PathBuf}; use std::rc::Rc; -use std::cmp; use std::env; -use std::{fmt, fs}; +use std::fs; use std::io::{self, Read}; - -use serialize::{Encodable, Decodable, Encoder, Decoder}; +pub use syntax_pos::*; +use errors::CodeMapper; use ast::Name; -// _____________________________________________________________________________ -// Pos, BytePos, CharPos -// - -pub trait Pos { - fn from_usize(n: usize) -> Self; - fn to_usize(&self) -> usize; -} - -/// A byte offset. Keep this small (currently 32-bits), as AST contains -/// a lot of them. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] -pub struct BytePos(pub u32); - -/// A character offset. Because of multibyte utf8 characters, a byte offset -/// is not equivalent to a character offset. The CodeMap will convert BytePos -/// values to CharPos values as necessary. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] -pub struct CharPos(pub usize); - -// FIXME: Lots of boilerplate in these impls, but so far my attempts to fix -// have been unsuccessful - -impl Pos for BytePos { - fn from_usize(n: usize) -> BytePos { BytePos(n as u32) } - fn to_usize(&self) -> usize { let BytePos(n) = *self; n as usize } -} - -impl Add for BytePos { - type Output = BytePos; - - fn add(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() + rhs.to_usize()) as u32) - } -} - -impl Sub for BytePos { - type Output = BytePos; - - fn sub(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() - rhs.to_usize()) as u32) - } -} - -impl Encodable for BytePos { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_u32(self.0) - } -} - -impl Decodable for BytePos { - fn decode(d: &mut D) -> Result { - Ok(BytePos(d.read_u32()?)) - } -} - -impl Pos for CharPos { - fn from_usize(n: usize) -> CharPos { CharPos(n) } - fn to_usize(&self) -> usize { let CharPos(n) = *self; n } -} - -impl Add for CharPos { - type Output = CharPos; - - fn add(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() + rhs.to_usize()) - } -} - -impl Sub for CharPos { - type Output = CharPos; - - fn sub(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() - rhs.to_usize()) - } -} - -// _____________________________________________________________________________ -// Span, MultiSpan, Spanned -// - -/// Spans represent a region of code, used for error reporting. Positions in spans -/// are *absolute* positions from the beginning of the codemap, not positions -/// relative to FileMaps. Methods on the CodeMap can be used to relate spans back -/// to the original source. -/// You must be careful if the span crosses more than one file - you will not be -/// able to use many of the functions on spans in codemap and you cannot assume -/// that the length of the span = hi - lo; there may be space in the BytePos -/// range between files. -#[derive(Clone, Copy, Hash, PartialEq, Eq)] -pub struct Span { - pub lo: BytePos, - pub hi: BytePos, - /// Information about where the macro came from, if this piece of - /// code was created by a macro expansion. - pub expn_id: ExpnId -} - -/// A collection of spans. Spans have two orthogonal attributes: -/// -/// - they can be *primary spans*. In this case they are the locus of -/// the error, and would be rendered with `^^^`. -/// - they can have a *label*. In this case, the label is written next -/// to the mark in the snippet when we render. -#[derive(Clone)] -pub struct MultiSpan { - primary_spans: Vec, - span_labels: Vec<(Span, String)>, -} - -#[derive(Clone, Debug)] -pub struct SpanLabel { - /// The span we are going to include in the final snippet. - pub span: Span, - - /// Is this a primary span? This is the "locus" of the message, - /// and is indicated with a `^^^^` underline, versus `----`. - pub is_primary: bool, - - /// What label should we attach to this span (if any)? - pub label: Option, -} - -pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION }; - -// Generic span to be used for code originating from the command line -pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0), - hi: BytePos(0), - expn_id: COMMAND_LINE_EXPN }; - -impl Span { - /// Returns a new span representing just the end-point of this span - pub fn end_point(self) -> Span { - let lo = cmp::max(self.hi.0 - 1, self.lo.0); - Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id} - } - - /// Returns `self` if `self` is not the dummy span, and `other` otherwise. - pub fn substitute_dummy(self, other: Span) -> Span { - if self.source_equal(&DUMMY_SP) { other } else { self } - } - - pub fn contains(self, other: Span) -> bool { - self.lo <= other.lo && other.hi <= self.hi - } - - /// Return true if the spans are equal with regards to the source text. - /// - /// Use this instead of `==` when either span could be generated code, - /// and you only care that they point to the same bytes of source text. - pub fn source_equal(&self, other: &Span) -> bool { - self.lo == other.lo && self.hi == other.hi - } - - /// Returns `Some(span)`, a union of `self` and `other`, on overlap. - pub fn merge(self, other: Span) -> Option { - if self.expn_id != other.expn_id { - return None; - } - - if (self.lo <= other.lo && self.hi > other.lo) || - (self.lo >= other.lo && self.lo < other.hi) { - Some(Span { - lo: cmp::min(self.lo, other.lo), - hi: cmp::max(self.hi, other.hi), - expn_id: self.expn_id, - }) - } else { - None - } - } - - /// Returns `Some(span)`, where the start is trimmed by the end of `other` - pub fn trim_start(self, other: Span) -> Option { - if self.hi > other.hi { - Some(Span { lo: cmp::max(self.lo, other.hi), .. self }) - } else { - None - } - } -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub struct Spanned { - pub node: T, - pub span: Span, -} - -impl Encodable for Span { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_struct("Span", 2, |s| { - s.emit_struct_field("lo", 0, |s| { - self.lo.encode(s) - })?; - - s.emit_struct_field("hi", 1, |s| { - self.hi.encode(s) - }) - }) - } -} - -impl Decodable for Span { - fn decode(d: &mut D) -> Result { - d.read_struct("Span", 2, |d| { - let lo = d.read_struct_field("lo", 0, |d| { - BytePos::decode(d) - })?; - - let hi = d.read_struct_field("hi", 1, |d| { - BytePos::decode(d) - })?; - - Ok(mk_sp(lo, hi)) - }) - } -} - -fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}", - span.lo, span.hi, span.expn_id) -} - -thread_local!(pub static SPAN_DEBUG: Cell fmt::Result> = - Cell::new(default_span_debug)); - -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - SPAN_DEBUG.with(|span_debug| span_debug.get()(*self, f)) - } -} - -pub fn spanned(lo: BytePos, hi: BytePos, t: T) -> Spanned { - respan(mk_sp(lo, hi), t) -} - -pub fn respan(sp: Span, t: T) -> Spanned { - Spanned {node: t, span: sp} -} - -pub fn dummy_spanned(t: T) -> Spanned { - respan(DUMMY_SP, t) -} - -/* assuming that we're not in macro expansion */ -pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span { - Span {lo: lo, hi: hi, expn_id: NO_EXPANSION} -} - /// Return the span itself if it doesn't come from a macro expansion, /// otherwise return the call site span up to the `enclosing_sp` by /// following the `expn_info` chain. @@ -295,123 +44,31 @@ pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span { } } -impl MultiSpan { - pub fn new() -> MultiSpan { - MultiSpan { - primary_spans: vec![], - span_labels: vec![] - } - } - - pub fn from_span(primary_span: Span) -> MultiSpan { - MultiSpan { - primary_spans: vec![primary_span], - span_labels: vec![] - } - } - - pub fn from_spans(vec: Vec) -> MultiSpan { - MultiSpan { - primary_spans: vec, - span_labels: vec![] - } - } - - pub fn push_span_label(&mut self, span: Span, label: String) { - self.span_labels.push((span, label)); - } - - /// Selects the first primary span (if any) - pub fn primary_span(&self) -> Option { - self.primary_spans.first().cloned() - } - - /// Returns all primary spans. - pub fn primary_spans(&self) -> &[Span] { - &self.primary_spans - } - - /// Returns the strings to highlight. We always ensure that there - /// is an entry for each of the primary spans -- for each primary - /// span P, if there is at least one label with span P, we return - /// those labels (marked as primary). But otherwise we return - /// `SpanLabel` instances with empty labels. - pub fn span_labels(&self) -> Vec { - let is_primary = |span| self.primary_spans.contains(&span); - let mut span_labels = vec![]; - - for &(span, ref label) in &self.span_labels { - span_labels.push(SpanLabel { - span: span, - is_primary: is_primary(span), - label: Some(label.clone()) - }); - } - - for &span in &self.primary_spans { - if !span_labels.iter().any(|sl| sl.span == span) { - span_labels.push(SpanLabel { - span: span, - is_primary: true, - label: None - }); - } - } - - span_labels - } +/// The source of expansion. +#[derive(Clone, Hash, Debug, PartialEq, Eq)] +pub enum ExpnFormat { + /// e.g. #[derive(...)] + MacroAttribute(Name), + /// e.g. `format!()` + MacroBang(Name), } -impl From for MultiSpan { - fn from(span: Span) -> MultiSpan { - MultiSpan::from_span(span) - } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub struct Spanned { + pub node: T, + pub span: Span, } -// _____________________________________________________________________________ -// Loc, LocWithOpt, FileMapAndLine, FileMapAndBytePos -// - -/// A source code location used for error reporting -#[derive(Debug)] -pub struct Loc { - /// Information about the original source - pub file: Rc, - /// The (1-based) line number - pub line: usize, - /// The (0-based) column offset - pub col: CharPos +pub fn spanned(lo: BytePos, hi: BytePos, t: T) -> Spanned { + respan(mk_sp(lo, hi), t) } -/// A source code location used as the result of lookup_char_pos_adj -// Actually, *none* of the clients use the filename *or* file field; -// perhaps they should just be removed. -#[derive(Debug)] -pub struct LocWithOpt { - pub filename: FileName, - pub line: usize, - pub col: CharPos, - pub file: Option>, +pub fn respan(sp: Span, t: T) -> Spanned { + Spanned {node: t, span: sp} } -// used to be structural records. Better names, anyone? -#[derive(Debug)] -pub struct FileMapAndLine { pub fm: Rc, pub line: usize } -#[derive(Debug)] -pub struct FileMapAndBytePos { pub fm: Rc, pub pos: BytePos } - - -// _____________________________________________________________________________ -// ExpnFormat, NameAndSpan, ExpnInfo, ExpnId -// - -/// The source of expansion. -#[derive(Clone, Hash, Debug, PartialEq, Eq)] -pub enum ExpnFormat { - /// e.g. #[derive(...)] - MacroAttribute(Name), - /// e.g. `format!()` - MacroBang(Name), +pub fn dummy_spanned(t: T) -> Spanned { + respan(DUMMY_SP, t) } #[derive(Clone, Hash, Debug)] @@ -454,257 +111,10 @@ pub struct ExpnInfo { pub callee: NameAndSpan } -#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy)] -pub struct ExpnId(u32); - -pub const NO_EXPANSION: ExpnId = ExpnId(!0); -// For code appearing from the command line -pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1); - -impl ExpnId { - pub fn from_u32(id: u32) -> ExpnId { - ExpnId(id) - } - - pub fn into_u32(self) -> u32 { - self.0 - } -} - // _____________________________________________________________________________ // FileMap, MultiByteChar, FileName, FileLines // -pub type FileName = String; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct LineInfo { - /// Index of line, starting from 0. - pub line_index: usize, - - /// Column in line where span begins, starting from 0. - pub start_col: CharPos, - - /// Column in line where span ends, starting from 0, exclusive. - pub end_col: CharPos, -} - -pub struct FileLines { - pub file: Rc, - pub lines: Vec -} - -/// Identifies an offset of a multi-byte character in a FileMap -#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)] -pub struct MultiByteChar { - /// The absolute offset of the character in the CodeMap - pub pos: BytePos, - /// The number of bytes, >=2 - pub bytes: usize, -} - -/// A single source in the CodeMap. -pub struct FileMap { - /// The name of the file that the source came from, source that doesn't - /// originate from files has names between angle brackets by convention, - /// e.g. `` - pub name: FileName, - /// The absolute path of the file that the source came from. - pub abs_path: Option, - /// The complete source code - pub src: Option>, - /// The start position of this source in the CodeMap - pub start_pos: BytePos, - /// The end position of this source in the CodeMap - pub end_pos: BytePos, - /// Locations of lines beginnings in the source code - pub lines: RefCell>, - /// Locations of multi-byte characters in the source code - pub multibyte_chars: RefCell>, -} - -impl Encodable for FileMap { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_struct("FileMap", 6, |s| { - s.emit_struct_field("name", 0, |s| self.name.encode(s))?; - s.emit_struct_field("abs_path", 1, |s| self.abs_path.encode(s))?; - s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))?; - s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))?; - s.emit_struct_field("lines", 4, |s| { - let lines = self.lines.borrow(); - // store the length - s.emit_u32(lines.len() as u32)?; - - if !lines.is_empty() { - // In order to preserve some space, we exploit the fact that - // the lines list is sorted and individual lines are - // probably not that long. Because of that we can store lines - // as a difference list, using as little space as possible - // for the differences. - let max_line_length = if lines.len() == 1 { - 0 - } else { - lines.windows(2) - .map(|w| w[1] - w[0]) - .map(|bp| bp.to_usize()) - .max() - .unwrap() - }; - - let bytes_per_diff: u8 = match max_line_length { - 0 ... 0xFF => 1, - 0x100 ... 0xFFFF => 2, - _ => 4 - }; - - // Encode the number of bytes used per diff. - bytes_per_diff.encode(s)?; - - // Encode the first element. - lines[0].encode(s)?; - - let diff_iter = (&lines[..]).windows(2) - .map(|w| (w[1] - w[0])); - - match bytes_per_diff { - 1 => for diff in diff_iter { (diff.0 as u8).encode(s)? }, - 2 => for diff in diff_iter { (diff.0 as u16).encode(s)? }, - 4 => for diff in diff_iter { diff.0.encode(s)? }, - _ => unreachable!() - } - } - - Ok(()) - })?; - s.emit_struct_field("multibyte_chars", 5, |s| { - (*self.multibyte_chars.borrow()).encode(s) - }) - }) - } -} - -impl Decodable for FileMap { - fn decode(d: &mut D) -> Result { - - d.read_struct("FileMap", 6, |d| { - let name: String = d.read_struct_field("name", 0, |d| Decodable::decode(d))?; - let abs_path: Option = - d.read_struct_field("abs_path", 1, |d| Decodable::decode(d))?; - let start_pos: BytePos = d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?; - let end_pos: BytePos = d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))?; - let lines: Vec = d.read_struct_field("lines", 4, |d| { - let num_lines: u32 = Decodable::decode(d)?; - let mut lines = Vec::with_capacity(num_lines as usize); - - if num_lines > 0 { - // Read the number of bytes used per diff. - let bytes_per_diff: u8 = Decodable::decode(d)?; - - // Read the first element. - let mut line_start: BytePos = Decodable::decode(d)?; - lines.push(line_start); - - for _ in 1..num_lines { - let diff = match bytes_per_diff { - 1 => d.read_u8()? as u32, - 2 => d.read_u16()? as u32, - 4 => d.read_u32()?, - _ => unreachable!() - }; - - line_start = line_start + BytePos(diff); - - lines.push(line_start); - } - } - - Ok(lines) - })?; - let multibyte_chars: Vec = - d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?; - Ok(FileMap { - name: name, - abs_path: abs_path, - start_pos: start_pos, - end_pos: end_pos, - src: None, - lines: RefCell::new(lines), - multibyte_chars: RefCell::new(multibyte_chars) - }) - }) - } -} - -impl fmt::Debug for FileMap { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "FileMap({})", self.name) - } -} - -impl FileMap { - /// EFFECT: register a start-of-line offset in the - /// table of line-beginnings. - /// UNCHECKED INVARIANT: these offsets must be added in the right - /// order and must be in the right places; there is shared knowledge - /// about what ends a line between this file and parse.rs - /// WARNING: pos param here is the offset relative to start of CodeMap, - /// and CodeMap will append a newline when adding a filemap without a newline at the end, - /// so the safe way to call this is with value calculated as - /// filemap.start_pos + newline_offset_relative_to_the_start_of_filemap. - pub fn next_line(&self, pos: BytePos) { - // the new charpos must be > the last one (or it's the first one). - let mut lines = self.lines.borrow_mut(); - let line_len = lines.len(); - assert!(line_len == 0 || ((*lines)[line_len - 1] < pos)); - lines.push(pos); - } - - /// get a line from the list of pre-computed line-beginnings. - /// line-number here is 0-based. - pub fn get_line(&self, line_number: usize) -> Option<&str> { - match self.src { - Some(ref src) => { - let lines = self.lines.borrow(); - lines.get(line_number).map(|&line| { - let begin: BytePos = line - self.start_pos; - let begin = begin.to_usize(); - // We can't use `lines.get(line_number+1)` because we might - // be parsing when we call this function and thus the current - // line is the last one we have line info for. - let slice = &src[begin..]; - match slice.find('\n') { - Some(e) => &slice[..e], - None => slice - } - }) - } - None => None - } - } - - pub fn record_multibyte_char(&self, pos: BytePos, bytes: usize) { - assert!(bytes >=2 && bytes <= 4); - let mbc = MultiByteChar { - pos: pos, - bytes: bytes, - }; - self.multibyte_chars.borrow_mut().push(mbc); - } - - pub fn is_real_file(&self) -> bool { - !(self.name.starts_with("<") && - self.name.ends_with(">")) - } - - pub fn is_imported(&self) -> bool { - self.src.is_none() - } - - fn count_lines(&self) -> usize { - self.lines.borrow().len() - } -} - /// An abstraction over the fs operations used by the Parser. pub trait FileLoader { /// Query the existence of a file. @@ -1392,52 +802,24 @@ impl CodeMap { } } -pub struct MacroBacktrace { - /// span where macro was applied to generate this code - pub call_site: Span, - - /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") - pub macro_decl_name: String, - - /// span where macro was defined (if known) - pub def_site_span: Option, -} - -// _____________________________________________________________________________ -// SpanLinesError, SpanSnippetError, DistinctSources, MalformedCodemapPositions -// - -pub type FileLinesResult = Result; - -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum SpanLinesError { - IllFormedSpan(Span), - DistinctSources(DistinctSources), -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum SpanSnippetError { - IllFormedSpan(Span), - DistinctSources(DistinctSources), - MalformedForCodemap(MalformedCodemapPositions), - SourceNotAvailable { filename: String } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct DistinctSources { - begin: (String, BytePos), - end: (String, BytePos) -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct MalformedCodemapPositions { - name: String, - source_len: usize, - begin_pos: BytePos, - end_pos: BytePos +impl CodeMapper for CodeMap { + fn lookup_char_pos(&self, pos: BytePos) -> Loc { + self.lookup_char_pos(pos) + } + fn span_to_lines(&self, sp: Span) -> FileLinesResult { + self.span_to_lines(sp) + } + fn span_to_string(&self, sp: Span) -> String { + self.span_to_string(sp) + } + fn span_to_filename(&self, sp: Span) -> FileName { + self.span_to_filename(sp) + } + fn macro_backtrace(&self, span: Span) -> Vec { + self.macro_backtrace(span) + } } - // _____________________________________________________________________________ // Tests // @@ -1445,6 +827,13 @@ pub struct MalformedCodemapPositions { #[cfg(test)] mod tests { use super::*; + use errors::{Level, CodeSuggestion}; + use errors::emitter::EmitterWriter; + use errors::snippet::{SnippetData, RenderedLine, FormatMode}; + use std::sync::{Arc, Mutex}; + use std::io::{self, Write}; + use std::str::from_utf8; + use std::rc::Rc; #[test] fn t1 () { @@ -1688,6 +1077,69 @@ mod tests { blork.rs:1:1: 1:12\n `first line.`\n"); } + /// Returns the span corresponding to the `n`th occurrence of + /// `substring` in `source_text`. + trait CodeMapExtension { + fn span_substr(&self, + file: &Rc, + source_text: &str, + substring: &str, + n: usize) + -> Span; + } + + impl CodeMapExtension for CodeMap { + fn span_substr(&self, + file: &Rc, + source_text: &str, + substring: &str, + n: usize) + -> Span + { + println!("span_substr(file={:?}/{:?}, substring={:?}, n={})", + file.name, file.start_pos, substring, n); + let mut i = 0; + let mut hi = 0; + loop { + let offset = source_text[hi..].find(substring).unwrap_or_else(|| { + panic!("source_text `{}` does not have {} occurrences of `{}`, only {}", + source_text, n, substring, i); + }); + let lo = hi + offset; + hi = lo + substring.len(); + if i == n { + let span = Span { + lo: BytePos(lo as u32 + file.start_pos.0), + hi: BytePos(hi as u32 + file.start_pos.0), + expn_id: NO_EXPANSION, + }; + assert_eq!(&self.span_to_snippet(span).unwrap()[..], + substring); + return span; + } + i += 1; + } + } + } + + fn splice(start: Span, end: Span) -> Span { + Span { + lo: start.lo, + hi: end.hi, + expn_id: NO_EXPANSION, + } + } + + fn make_string(lines: &[RenderedLine]) -> String { + lines.iter() + .flat_map(|rl| { + rl.text.iter() + .map(|s| &s.text[..]) + .chain(Some("\n")) + }) + .collect() + } + fn init_expansion_chain(cm: &CodeMap) -> Span { // Creates an expansion chain containing two recursive calls // root -> expA -> expA -> expB -> expB -> end @@ -1767,4 +1219,761 @@ r"blork2.rs:2:1: 2:12 "; assert_eq!(sstr, res_str); } + + struct Sink(Arc>>); + impl Write for Sink { + fn write(&mut self, data: &[u8]) -> io::Result { + Write::write(&mut *self.0.lock().unwrap(), data) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } + } + + // Diagnostic doesn't align properly in span where line number increases by one digit + #[test] + fn test_hilight_suggestion_issue_11715() { + let data = Arc::new(Mutex::new(Vec::new())); + let cm = Rc::new(CodeMap::new()); + let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), + None, + cm.clone(), + FormatMode::NewErrorFormat); + let content = "abcdefg + koksi + line3 + line4 + cinq + line6 + line7 + line8 + line9 + line10 + e-lä-vän + tolv + dreizehn + "; + let file = cm.new_filemap_and_lines("dummy.txt", None, content); + let start = file.lines.borrow()[10]; + let end = file.lines.borrow()[11]; + let sp = mk_sp(start, end); + let lvl = Level::Error; + println!("highlight_lines"); + ew.highlight_lines(&sp.into(), lvl).unwrap(); + println!("done"); + let vec = data.lock().unwrap().clone(); + let vec: &[u8] = &vec; + let str = from_utf8(vec).unwrap(); + println!("r#\"\n{}\"#", str); + assert_eq!(str, &r#" + --> dummy.txt:11:1 + |> +11 |> e-lä-vän + |> ^ +"#[1..]); + } + + #[test] + fn test_single_span_splice() { + // Test that a `MultiSpan` containing a single span splices a substition correctly + let cm = CodeMap::new(); + let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; + let selection = " \n ~~\n~~~\n~~~~~ \n \n"; + cm.new_filemap_and_lines("blork.rs", None, inputtext); + let sp = span_from_selection(inputtext, selection); + let msp: MultiSpan = sp.into(); + + // check that we are extracting the text we thought we were extracting + assert_eq!(&cm.span_to_snippet(sp).unwrap(), "BB\nCCC\nDDDDD"); + + let substitute = "ZZZZZZ".to_owned(); + let expected = "bbbbZZZZZZddddd"; + let suggest = CodeSuggestion { + msp: msp, + substitutes: vec![substitute], + }; + assert_eq!(suggest.splice_lines(&cm), expected); + } + + #[test] + fn test_multi_span_splice() { + // Test that a `MultiSpan` containing multiple spans splices a substition correctly + let cm = CodeMap::new(); + let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; + let selection1 = " \n \n \n \n ~ \n"; // intentionally out of order + let selection2 = " \n ~~\n~~~\n~~~~~ \n \n"; + cm.new_filemap_and_lines("blork.rs", None, inputtext); + let sp1 = span_from_selection(inputtext, selection1); + let sp2 = span_from_selection(inputtext, selection2); + let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]); + + let expected = "bbbbZZZZZZddddd\neXYZe"; + let suggest = CodeSuggestion { + msp: msp, + substitutes: vec!["ZZZZZZ".to_owned(), + "XYZ".to_owned()] + }; + + assert_eq!(suggest.splice_lines(&cm), expected); + } + + #[test] + fn test_multispan_highlight() { + let data = Arc::new(Mutex::new(Vec::new())); + let cm = Rc::new(CodeMap::new()); + let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), + None, + cm.clone(), + FormatMode::NewErrorFormat); + + let inp = "_____aaaaaa____bbbbbb__cccccdd_"; + let sp1 = " ~~~~~~ "; + let sp2 = " ~~~~~~ "; + let sp3 = " ~~~~~ "; + let sp4 = " ~~~~ "; + let sp34 = " ~~~~~~~ "; + + let expect_start = &r#" + --> dummy.txt:1:6 + |> +1 |> _____aaaaaa____bbbbbb__cccccdd_ + |> ^^^^^^ ^^^^^^ ^^^^^^^ +"#[1..]; + + let span = |sp, expected| { + let sp = span_from_selection(inp, sp); + assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected); + sp + }; + cm.new_filemap_and_lines("dummy.txt", None, inp); + let sp1 = span(sp1, "aaaaaa"); + let sp2 = span(sp2, "bbbbbb"); + let sp3 = span(sp3, "ccccc"); + let sp4 = span(sp4, "ccdd"); + let sp34 = span(sp34, "cccccdd"); + + let spans = vec![sp1, sp2, sp3, sp4]; + + let test = |expected, highlight: &mut FnMut()| { + data.lock().unwrap().clear(); + highlight(); + let vec = data.lock().unwrap().clone(); + let actual = from_utf8(&vec[..]).unwrap(); + println!("actual=\n{}", actual); + assert_eq!(actual, expected); + }; + + let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]); + test(expect_start, &mut || { + diag.highlight_lines(&msp, Level::Error).unwrap(); + }); + test(expect_start, &mut || { + let msp = MultiSpan::from_spans(spans.clone()); + diag.highlight_lines(&msp, Level::Error).unwrap(); + }); + } + + #[test] + fn test_huge_multispan_highlight() { + let data = Arc::new(Mutex::new(Vec::new())); + let cm = Rc::new(CodeMap::new()); + let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), + None, + cm.clone(), + FormatMode::NewErrorFormat); + + let inp = "aaaaa\n\ + aaaaa\n\ + aaaaa\n\ + bbbbb\n\ + ccccc\n\ + xxxxx\n\ + yyyyy\n\ + _____\n\ + ddd__eee_\n\ + elided\n\ + __f_gg"; + let file = cm.new_filemap_and_lines("dummy.txt", None, inp); + + let span = |lo, hi, (off_lo, off_hi)| { + let lines = file.lines.borrow(); + let (mut lo, mut hi): (BytePos, BytePos) = (lines[lo], lines[hi]); + lo.0 += off_lo; + hi.0 += off_hi; + mk_sp(lo, hi) + }; + let sp0 = span(4, 6, (0, 5)); + let sp1 = span(0, 6, (0, 5)); + let sp2 = span(8, 8, (0, 3)); + let sp3 = span(8, 8, (5, 8)); + let sp4 = span(10, 10, (2, 3)); + let sp5 = span(10, 10, (4, 6)); + + let expect0 = &r#" + --> dummy.txt:5:1 + |> +5 |> ccccc + |> ^ +... +9 |> ddd__eee_ + |> ^^^ ^^^ +10 |> elided +11 |> __f_gg + |> ^ ^^ +"#[1..]; + + let expect = &r#" + --> dummy.txt:1:1 + |> +1 |> aaaaa + |> ^ +... +9 |> ddd__eee_ + |> ^^^ ^^^ +10 |> elided +11 |> __f_gg + |> ^ ^^ +"#[1..]; + + macro_rules! test { + ($expected: expr, $highlight: expr) => ({ + data.lock().unwrap().clear(); + $highlight(); + let vec = data.lock().unwrap().clone(); + let actual = from_utf8(&vec[..]).unwrap(); + println!("actual:"); + println!("{}", actual); + println!("expected:"); + println!("{}", $expected); + assert_eq!(&actual[..], &$expected[..]); + }); + } + + let msp0 = MultiSpan::from_spans(vec![sp0, sp2, sp3, sp4, sp5]); + let msp = MultiSpan::from_spans(vec![sp1, sp2, sp3, sp4, sp5]); + + test!(expect0, || { + diag.highlight_lines(&msp0, Level::Error).unwrap(); + }); + test!(expect, || { + diag.highlight_lines(&msp, Level::Error).unwrap(); + }); + } + + #[test] + fn tab() { + let file_text = " +fn foo() { +\tbar; +} +"; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + let span_bar = cm.span_substr(&foo, file_text, "bar", 0); + + let mut snippet = SnippetData::new(cm, Some(span_bar), FormatMode::NewErrorFormat); + snippet.push(span_bar, true, None); + + let lines = snippet.render_lines(); + let text = make_string(&lines); + assert_eq!(&text[..], &" + --> foo.rs:3:2 + |> +3 |> \tbar; + |> \t^^^ +"[1..]); + } + + #[test] + fn one_line() { + let file_text = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0); + let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1); + let span_semi = cm.span_substr(&foo, file_text, ";", 0); + + let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat); + snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here"))); + snippet.push(span_vec1, false, Some(format!("error occurs here"))); + snippet.push(span_semi, false, Some(format!("previous borrow ends here"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + + let text: String = make_string(&lines); + + println!("text=\n{}", text); + assert_eq!(&text[..], &r#" + ::: foo.rs + |> +3 |> vec.push(vec.pop().unwrap()); + |> --- --- - previous borrow ends here + |> | | + |> | error occurs here + |> previous borrow of `vec` occurs here +"#[1..]); + } + + #[test] + fn two_files() { + let file_text_foo = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let file_text_bar = r#" +fn bar() { + // these blank links here + // serve to ensure that the line numbers + // from bar.rs + // require more digits + + + + + + + + + + + vec.push(); + + // this line will get elided + + vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo_map = cm.new_filemap_and_lines("foo.rs", None, file_text_foo); + let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0); + let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1); + let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0); + + let bar_map = cm.new_filemap_and_lines("bar.rs", None, file_text_bar); + let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0); + let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1); + let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0); + + let mut snippet = SnippetData::new(cm, Some(span_foo_vec1), FormatMode::NewErrorFormat); + snippet.push(span_foo_vec0, false, Some(format!("a"))); + snippet.push(span_foo_vec1, true, Some(format!("b"))); + snippet.push(span_foo_semi, false, Some(format!("c"))); + snippet.push(span_bar_vec0, false, Some(format!("d"))); + snippet.push(span_bar_vec1, false, Some(format!("e"))); + snippet.push(span_bar_semi, false, Some(format!("f"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + + let text: String = make_string(&lines); + + println!("text=\n{}", text); + + // Note that the `|>` remain aligned across both files: + assert_eq!(&text[..], &r#" + --> foo.rs:3:14 + |> +3 |> vec.push(vec.pop().unwrap()); + |> --- ^^^ - c + |> | | + |> | b + |> a + ::: bar.rs + |> +17 |> vec.push(); + |> --- - f + |> | + |> d +... +21 |> vec.pop().unwrap()); + |> --- e +"#[1..]); + } + + #[test] + fn multi_line() { + let file_text = r#" +fn foo() { + let name = find_id(&data, 22).unwrap(); + + // Add one more item we forgot to the vector. Silly us. + data.push(Data { name: format!("Hera"), id: 66 }); + + // Print everything out. + println!("Name: {:?}", name); + println!("Data: {:?}", data); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + let span_data0 = cm.span_substr(&foo, file_text, "data", 0); + let span_data1 = cm.span_substr(&foo, file_text, "data", 1); + let span_rbrace = cm.span_substr(&foo, file_text, "}", 3); + + let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat); + snippet.push(span_data0, false, Some(format!("immutable borrow begins here"))); + snippet.push(span_data1, false, Some(format!("mutable borrow occurs here"))); + snippet.push(span_rbrace, false, Some(format!("immutable borrow ends here"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + + let text: String = make_string(&lines); + + println!("text=\n{}", text); + assert_eq!(&text[..], &r#" + ::: foo.rs + |> +3 |> let name = find_id(&data, 22).unwrap(); + |> ---- immutable borrow begins here +... +6 |> data.push(Data { name: format!("Hera"), id: 66 }); + |> ---- mutable borrow occurs here +... +11 |> } + |> - immutable borrow ends here +"#[1..]); + } + + #[test] + fn overlapping() { + let file_text = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + let span0 = cm.span_substr(&foo, file_text, "vec.push", 0); + let span1 = cm.span_substr(&foo, file_text, "vec", 0); + let span2 = cm.span_substr(&foo, file_text, "ec.push", 0); + let span3 = cm.span_substr(&foo, file_text, "unwrap", 0); + + let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat); + snippet.push(span0, false, Some(format!("A"))); + snippet.push(span1, false, Some(format!("B"))); + snippet.push(span2, false, Some(format!("C"))); + snippet.push(span3, false, Some(format!("D"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + let text: String = make_string(&lines); + + println!("text=r#\"\n{}\".trim_left()", text); + assert_eq!(&text[..], &r#" + ::: foo.rs + |> +3 |> vec.push(vec.pop().unwrap()); + |> -------- ------ D + |> || + |> |C + |> A + |> B +"#[1..]); + } + + #[test] + fn one_line_out_of_order() { + let file_text = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0); + let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1); + let span_semi = cm.span_substr(&foo, file_text, ";", 0); + + // intentionally don't push the snippets left to right + let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat); + snippet.push(span_vec1, false, Some(format!("error occurs here"))); + snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here"))); + snippet.push(span_semi, false, Some(format!("previous borrow ends here"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + let text: String = make_string(&lines); + + println!("text=r#\"\n{}\".trim_left()", text); + assert_eq!(&text[..], &r#" + ::: foo.rs + |> +3 |> vec.push(vec.pop().unwrap()); + |> --- --- - previous borrow ends here + |> | | + |> | error occurs here + |> previous borrow of `vec` occurs here +"#[1..]); + } + + #[test] + fn elide_unnecessary_lines() { + let file_text = r#" +fn foo() { + let mut vec = vec![0, 1, 2]; + let mut vec2 = vec; + vec2.push(3); + vec2.push(4); + vec2.push(5); + vec2.push(6); + vec.push(7); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3); + let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8); + + let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat); + snippet.push(span_vec0, false, Some(format!("`vec` moved here because it \ + has type `collections::vec::Vec`"))); + snippet.push(span_vec1, false, Some(format!("use of moved value: `vec`"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + let text: String = make_string(&lines); + println!("text=r#\"\n{}\".trim_left()", text); + assert_eq!(&text[..], &r#" + ::: foo.rs + |> +4 |> let mut vec2 = vec; + |> --- `vec` moved here because it has type `collections::vec::Vec` +... +9 |> vec.push(7); + |> --- use of moved value: `vec` +"#[1..]); + } + + #[test] + fn spans_without_labels() { + let file_text = r#" +fn foo() { + let mut vec = vec![0, 1, 2]; + let mut vec2 = vec; + vec2.push(3); + vec2.push(4); + vec2.push(5); + vec2.push(6); + vec.push(7); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + + let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat); + for i in 0..4 { + let span_veci = cm.span_substr(&foo, file_text, "vec", i); + snippet.push(span_veci, false, None); + } + + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("text=&r#\"\n{}\n\"#[1..]", text); + assert_eq!(text, &r#" + ::: foo.rs + |> +3 |> let mut vec = vec![0, 1, 2]; + |> --- --- +4 |> let mut vec2 = vec; + |> --- --- +"#[1..]); + } + + #[test] + fn span_long_selection() { + let file_text = r#" +impl SomeTrait for () { + fn foo(x: u32) { + // impl 1 + // impl 2 + // impl 3 + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + + let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat); + let fn_span = cm.span_substr(&foo, file_text, "fn", 0); + let rbrace_span = cm.span_substr(&foo, file_text, "}", 0); + snippet.push(splice(fn_span, rbrace_span), false, None); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" + ::: foo.rs + |> +3 |> fn foo(x: u32) { + |> - +"#[1..]); + } + + #[test] + fn span_overlap_label() { + // Test that we don't put `x_span` to the right of its highlight, + // since there is another highlight that overlaps it. + + let file_text = r#" + fn foo(x: u32) { + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + + let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat); + let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0); + let x_span = cm.span_substr(&foo, file_text, "x", 0); + snippet.push(fn_span, false, Some(format!("fn_span"))); + snippet.push(x_span, false, Some(format!("x_span"))); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" + ::: foo.rs + |> +2 |> fn foo(x: u32) { + |> -------------- + |> | | + |> | x_span + |> fn_span +"#[1..]); + } + + #[test] + fn span_overlap_label2() { + // Test that we don't put `x_span` to the right of its highlight, + // since there is another highlight that overlaps it. In this + // case, the overlap is only at the beginning, but it's still + // better to show the beginning more clearly. + + let file_text = r#" + fn foo(x: u32) { + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + + let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat); + let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0); + let x_span = cm.span_substr(&foo, file_text, "x: u32)", 0); + snippet.push(fn_span, false, Some(format!("fn_span"))); + snippet.push(x_span, false, Some(format!("x_span"))); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" + ::: foo.rs + |> +2 |> fn foo(x: u32) { + |> -------------- + |> | | + |> | x_span + |> fn_span +"#[1..]); + } + + #[test] + fn span_overlap_label3() { + // Test that we don't put `x_span` to the right of its highlight, + // since there is another highlight that overlaps it. In this + // case, the overlap is only at the beginning, but it's still + // better to show the beginning more clearly. + + let file_text = r#" + fn foo() { + let closure = || { + inner + }; + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + + let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat); + + let closure_span = { + let closure_start_span = cm.span_substr(&foo, file_text, "||", 0); + let closure_end_span = cm.span_substr(&foo, file_text, "}", 0); + splice(closure_start_span, closure_end_span) + }; + + let inner_span = cm.span_substr(&foo, file_text, "inner", 0); + + snippet.push(closure_span, false, Some(format!("foo"))); + snippet.push(inner_span, false, Some(format!("bar"))); + + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" + ::: foo.rs + |> +3 |> let closure = || { + |> - foo +4 |> inner + |> ----- bar +"#[1..]); + } + + #[test] + fn span_empty() { + // In one of the unit tests, we found that the parser sometimes + // gives empty spans, and in particular it supplied an EOF span + // like this one, which points at the very end. We want to + // fallback gracefully in this case. + + let file_text = r#" +fn main() { + struct Foo; + + impl !Sync for Foo {} + + unsafe impl Send for &'static Foo { + // error: cross-crate traits with a default impl, like `core::marker::Send`, + // can only be implemented for a struct/enum type, not + // `&'static Foo` +}"#; + + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); + + let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1); + rbrace_span.lo = rbrace_span.hi; + + let mut snippet = SnippetData::new(cm.clone(), + Some(rbrace_span), + FormatMode::NewErrorFormat); + snippet.push(rbrace_span, false, None); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" + --> foo.rs:11:2 + |> +11 |> } + |> - +"#[1..]); + } } diff --git a/syntex_syntax/src/config.rs b/syntex_syntax/src/config.rs index 0e5d6841..eaf82f5f 100644 --- a/syntex_syntax/src/config.rs +++ b/syntex_syntax/src/config.rs @@ -11,7 +11,8 @@ use attr::{AttrMetaMethods, HasAttrs}; use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; use fold::Folder; -use {ast, fold, attr}; +use {fold, attr}; +use ast; use codemap::{Spanned, respan}; use parse::{ParseSess, token}; use ptr::P; @@ -212,19 +213,7 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { } fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { - let is_item = match stmt.node { - ast::StmtKind::Decl(ref decl, _) => match decl.node { - ast::DeclKind::Item(_) => true, - _ => false, - }, - _ => false, - }; - - // avoid calling `visit_stmt_or_expr_attrs` on items - if !is_item { - self.visit_stmt_or_expr_attrs(stmt.attrs()); - } - + self.visit_stmt_or_expr_attrs(stmt.attrs()); self.configure(stmt).map(|stmt| fold::noop_fold_stmt(stmt, self)) .unwrap_or(SmallVector::zero()) } diff --git a/syntex_syntax/src/diagnostics/metadata.rs b/syntex_syntax/src/diagnostics/metadata.rs index 181b3259..5bbd18bd 100644 --- a/syntex_syntax/src/diagnostics/metadata.rs +++ b/syntex_syntax/src/diagnostics/metadata.rs @@ -20,7 +20,7 @@ use std::io::Write; use std::error::Error; use rustc_serialize::json::as_json; -use codemap::Span; +use syntax_pos::Span; use ext::base::ExtCtxt; use diagnostics::plugin::{ErrorMap, ErrorInfo}; diff --git a/syntex_syntax/src/diagnostics/plugin.rs b/syntex_syntax/src/diagnostics/plugin.rs index 26088b12..4e50299e 100644 --- a/syntex_syntax/src/diagnostics/plugin.rs +++ b/syntex_syntax/src/diagnostics/plugin.rs @@ -13,16 +13,19 @@ use std::collections::BTreeMap; use std::env; use ast; -use ast::{Ident, Name, TokenTree}; -use codemap::Span; +use ast::{Ident, Name}; +use syntax_pos::Span; use ext::base::{ExtCtxt, MacEager, MacResult}; use ext::build::AstBuilder; use parse::token; use ptr::P; +use tokenstream::{TokenTree}; use util::small_vector::SmallVector; use diagnostics::metadata::output_metadata; +pub use errors::*; + // Maximum width of any line in an extended error description (inclusive). const MAX_DESCRIPTION_WIDTH: usize = 80; diff --git a/syntex_syntax/src/errors/snippet/test.rs b/syntex_syntax/src/errors/snippet/test.rs deleted file mode 100644 index 79e40a09..00000000 --- a/syntex_syntax/src/errors/snippet/test.rs +++ /dev/null @@ -1,597 +0,0 @@ -// Copyright 2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Code for testing annotated snippets. - -#![cfg(test)] - -use codemap::{BytePos, CodeMap, FileMap, NO_EXPANSION, Span}; -use std::rc::Rc; -use super::{RenderedLine, SnippetData}; - -/// Returns the span corresponding to the `n`th occurrence of -/// `substring` in `source_text`. -trait CodeMapExtension { - fn span_substr(&self, - file: &Rc, - source_text: &str, - substring: &str, - n: usize) - -> Span; -} - -impl CodeMapExtension for CodeMap { - fn span_substr(&self, - file: &Rc, - source_text: &str, - substring: &str, - n: usize) - -> Span - { - println!("span_substr(file={:?}/{:?}, substring={:?}, n={})", - file.name, file.start_pos, substring, n); - let mut i = 0; - let mut hi = 0; - loop { - let offset = source_text[hi..].find(substring).unwrap_or_else(|| { - panic!("source_text `{}` does not have {} occurrences of `{}`, only {}", - source_text, n, substring, i); - }); - let lo = hi + offset; - hi = lo + substring.len(); - if i == n { - let span = Span { - lo: BytePos(lo as u32 + file.start_pos.0), - hi: BytePos(hi as u32 + file.start_pos.0), - expn_id: NO_EXPANSION, - }; - assert_eq!(&self.span_to_snippet(span).unwrap()[..], - substring); - return span; - } - i += 1; - } - } -} - -fn splice(start: Span, end: Span) -> Span { - Span { - lo: start.lo, - hi: end.hi, - expn_id: NO_EXPANSION, - } -} - -fn make_string(lines: &[RenderedLine]) -> String { - lines.iter() - .flat_map(|rl| { - rl.text.iter() - .map(|s| &s.text[..]) - .chain(Some("\n")) - }) - .collect() -} - -#[test] -fn tab() { - let file_text = " -fn foo() { -\tbar; -} -"; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - let span_bar = cm.span_substr(&foo, file_text, "bar", 0); - - let mut snippet = SnippetData::new(cm, Some(span_bar)); - snippet.push(span_bar, true, None); - - let lines = snippet.render_lines(); - let text = make_string(&lines); - assert_eq!(&text[..], &" - --> foo.rs:3:2 - |> -3 |> \tbar; - |> \t^^^ -"[1..]); -} - -#[test] -fn one_line() { - let file_text = r#" -fn foo() { - vec.push(vec.pop().unwrap()); -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0); - let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1); - let span_semi = cm.span_substr(&foo, file_text, ";", 0); - - let mut snippet = SnippetData::new(cm, None); - snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here"))); - snippet.push(span_vec1, false, Some(format!("error occurs here"))); - snippet.push(span_semi, false, Some(format!("previous borrow ends here"))); - - let lines = snippet.render_lines(); - println!("{:#?}", lines); - - let text: String = make_string(&lines); - - println!("text=\n{}", text); - assert_eq!(&text[..], &r#" - ::: foo.rs - |> -3 |> vec.push(vec.pop().unwrap()); - |> --- --- - previous borrow ends here - |> | | - |> | error occurs here - |> previous borrow of `vec` occurs here -"#[1..]); -} - -#[test] -fn two_files() { - let file_text_foo = r#" -fn foo() { - vec.push(vec.pop().unwrap()); -} -"#; - - let file_text_bar = r#" -fn bar() { - // these blank links here - // serve to ensure that the line numbers - // from bar.rs - // require more digits - - - - - - - - - - - vec.push(); - - // this line will get elided - - vec.pop().unwrap()); -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo_map = cm.new_filemap_and_lines("foo.rs", None, file_text_foo); - let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0); - let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1); - let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0); - - let bar_map = cm.new_filemap_and_lines("bar.rs", None, file_text_bar); - let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0); - let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1); - let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0); - - let mut snippet = SnippetData::new(cm, Some(span_foo_vec1)); - snippet.push(span_foo_vec0, false, Some(format!("a"))); - snippet.push(span_foo_vec1, true, Some(format!("b"))); - snippet.push(span_foo_semi, false, Some(format!("c"))); - snippet.push(span_bar_vec0, false, Some(format!("d"))); - snippet.push(span_bar_vec1, false, Some(format!("e"))); - snippet.push(span_bar_semi, false, Some(format!("f"))); - - let lines = snippet.render_lines(); - println!("{:#?}", lines); - - let text: String = make_string(&lines); - - println!("text=\n{}", text); - - // Note that the `|>` remain aligned across both files: - assert_eq!(&text[..], &r#" - --> foo.rs:3:14 - |> -3 |> vec.push(vec.pop().unwrap()); - |> --- ^^^ - c - |> | | - |> | b - |> a - ::: bar.rs - |> -17 |> vec.push(); - |> --- - f - |> | - |> d -... -21 |> vec.pop().unwrap()); - |> --- e -"#[1..]); -} - -#[test] -fn multi_line() { - let file_text = r#" -fn foo() { - let name = find_id(&data, 22).unwrap(); - - // Add one more item we forgot to the vector. Silly us. - data.push(Data { name: format!("Hera"), id: 66 }); - - // Print everything out. - println!("Name: {:?}", name); - println!("Data: {:?}", data); -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - let span_data0 = cm.span_substr(&foo, file_text, "data", 0); - let span_data1 = cm.span_substr(&foo, file_text, "data", 1); - let span_rbrace = cm.span_substr(&foo, file_text, "}", 3); - - let mut snippet = SnippetData::new(cm, None); - snippet.push(span_data0, false, Some(format!("immutable borrow begins here"))); - snippet.push(span_data1, false, Some(format!("mutable borrow occurs here"))); - snippet.push(span_rbrace, false, Some(format!("immutable borrow ends here"))); - - let lines = snippet.render_lines(); - println!("{:#?}", lines); - - let text: String = make_string(&lines); - - println!("text=\n{}", text); - assert_eq!(&text[..], &r#" - ::: foo.rs - |> -3 |> let name = find_id(&data, 22).unwrap(); - |> ---- immutable borrow begins here -... -6 |> data.push(Data { name: format!("Hera"), id: 66 }); - |> ---- mutable borrow occurs here -... -11 |> } - |> - immutable borrow ends here -"#[1..]); -} - -#[test] -fn overlapping() { - let file_text = r#" -fn foo() { - vec.push(vec.pop().unwrap()); -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - let span0 = cm.span_substr(&foo, file_text, "vec.push", 0); - let span1 = cm.span_substr(&foo, file_text, "vec", 0); - let span2 = cm.span_substr(&foo, file_text, "ec.push", 0); - let span3 = cm.span_substr(&foo, file_text, "unwrap", 0); - - let mut snippet = SnippetData::new(cm, None); - snippet.push(span0, false, Some(format!("A"))); - snippet.push(span1, false, Some(format!("B"))); - snippet.push(span2, false, Some(format!("C"))); - snippet.push(span3, false, Some(format!("D"))); - - let lines = snippet.render_lines(); - println!("{:#?}", lines); - let text: String = make_string(&lines); - - println!("text=r#\"\n{}\".trim_left()", text); - assert_eq!(&text[..], &r#" - ::: foo.rs - |> -3 |> vec.push(vec.pop().unwrap()); - |> -------- ------ D - |> || - |> |C - |> A - |> B -"#[1..]); -} - -#[test] -fn one_line_out_of_order() { - let file_text = r#" -fn foo() { - vec.push(vec.pop().unwrap()); -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0); - let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1); - let span_semi = cm.span_substr(&foo, file_text, ";", 0); - - // intentionally don't push the snippets left to right - let mut snippet = SnippetData::new(cm, None); - snippet.push(span_vec1, false, Some(format!("error occurs here"))); - snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here"))); - snippet.push(span_semi, false, Some(format!("previous borrow ends here"))); - - let lines = snippet.render_lines(); - println!("{:#?}", lines); - let text: String = make_string(&lines); - - println!("text=r#\"\n{}\".trim_left()", text); - assert_eq!(&text[..], &r#" - ::: foo.rs - |> -3 |> vec.push(vec.pop().unwrap()); - |> --- --- - previous borrow ends here - |> | | - |> | error occurs here - |> previous borrow of `vec` occurs here -"#[1..]); -} - -#[test] -fn elide_unnecessary_lines() { - let file_text = r#" -fn foo() { - let mut vec = vec![0, 1, 2]; - let mut vec2 = vec; - vec2.push(3); - vec2.push(4); - vec2.push(5); - vec2.push(6); - vec.push(7); -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3); - let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8); - - let mut snippet = SnippetData::new(cm, None); - snippet.push(span_vec0, false, Some(format!("`vec` moved here because it \ - has type `collections::vec::Vec`"))); - snippet.push(span_vec1, false, Some(format!("use of moved value: `vec`"))); - - let lines = snippet.render_lines(); - println!("{:#?}", lines); - let text: String = make_string(&lines); - println!("text=r#\"\n{}\".trim_left()", text); - assert_eq!(&text[..], &r#" - ::: foo.rs - |> -4 |> let mut vec2 = vec; - |> --- `vec` moved here because it has type `collections::vec::Vec` -... -9 |> vec.push(7); - |> --- use of moved value: `vec` -"#[1..]); -} - -#[test] -fn spans_without_labels() { - let file_text = r#" -fn foo() { - let mut vec = vec![0, 1, 2]; - let mut vec2 = vec; - vec2.push(3); - vec2.push(4); - vec2.push(5); - vec2.push(6); - vec.push(7); -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - - let mut snippet = SnippetData::new(cm.clone(), None); - for i in 0..4 { - let span_veci = cm.span_substr(&foo, file_text, "vec", i); - snippet.push(span_veci, false, None); - } - - let lines = snippet.render_lines(); - let text: String = make_string(&lines); - println!("text=&r#\"\n{}\n\"#[1..]", text); - assert_eq!(text, &r#" - ::: foo.rs - |> -3 |> let mut vec = vec![0, 1, 2]; - |> --- --- -4 |> let mut vec2 = vec; - |> --- --- -"#[1..]); -} - -#[test] -fn span_long_selection() { - let file_text = r#" -impl SomeTrait for () { - fn foo(x: u32) { - // impl 1 - // impl 2 - // impl 3 - } -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - - let mut snippet = SnippetData::new(cm.clone(), None); - let fn_span = cm.span_substr(&foo, file_text, "fn", 0); - let rbrace_span = cm.span_substr(&foo, file_text, "}", 0); - snippet.push(splice(fn_span, rbrace_span), false, None); - let lines = snippet.render_lines(); - let text: String = make_string(&lines); - println!("r#\"\n{}\"", text); - assert_eq!(text, &r#" - ::: foo.rs - |> -3 |> fn foo(x: u32) { - |> - -"#[1..]); -} - -#[test] -fn span_overlap_label() { - // Test that we don't put `x_span` to the right of its highlight, - // since there is another highlight that overlaps it. - - let file_text = r#" - fn foo(x: u32) { - } -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - - let mut snippet = SnippetData::new(cm.clone(), None); - let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0); - let x_span = cm.span_substr(&foo, file_text, "x", 0); - snippet.push(fn_span, false, Some(format!("fn_span"))); - snippet.push(x_span, false, Some(format!("x_span"))); - let lines = snippet.render_lines(); - let text: String = make_string(&lines); - println!("r#\"\n{}\"", text); - assert_eq!(text, &r#" - ::: foo.rs - |> -2 |> fn foo(x: u32) { - |> -------------- - |> | | - |> | x_span - |> fn_span -"#[1..]); -} - -#[test] -fn span_overlap_label2() { - // Test that we don't put `x_span` to the right of its highlight, - // since there is another highlight that overlaps it. In this - // case, the overlap is only at the beginning, but it's still - // better to show the beginning more clearly. - - let file_text = r#" - fn foo(x: u32) { - } -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - - let mut snippet = SnippetData::new(cm.clone(), None); - let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0); - let x_span = cm.span_substr(&foo, file_text, "x: u32)", 0); - snippet.push(fn_span, false, Some(format!("fn_span"))); - snippet.push(x_span, false, Some(format!("x_span"))); - let lines = snippet.render_lines(); - let text: String = make_string(&lines); - println!("r#\"\n{}\"", text); - assert_eq!(text, &r#" - ::: foo.rs - |> -2 |> fn foo(x: u32) { - |> -------------- - |> | | - |> | x_span - |> fn_span -"#[1..]); -} - -#[test] -fn span_overlap_label3() { - // Test that we don't put `x_span` to the right of its highlight, - // since there is another highlight that overlaps it. In this - // case, the overlap is only at the beginning, but it's still - // better to show the beginning more clearly. - - let file_text = r#" - fn foo() { - let closure = || { - inner - }; - } -} -"#; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - - let mut snippet = SnippetData::new(cm.clone(), None); - - let closure_span = { - let closure_start_span = cm.span_substr(&foo, file_text, "||", 0); - let closure_end_span = cm.span_substr(&foo, file_text, "}", 0); - splice(closure_start_span, closure_end_span) - }; - - let inner_span = cm.span_substr(&foo, file_text, "inner", 0); - - snippet.push(closure_span, false, Some(format!("foo"))); - snippet.push(inner_span, false, Some(format!("bar"))); - - let lines = snippet.render_lines(); - let text: String = make_string(&lines); - println!("r#\"\n{}\"", text); - assert_eq!(text, &r#" - ::: foo.rs - |> -3 |> let closure = || { - |> - foo -4 |> inner - |> ----- bar -"#[1..]); -} - -#[test] -fn span_empty() { - // In one of the unit tests, we found that the parser sometimes - // gives empty spans, and in particular it supplied an EOF span - // like this one, which points at the very end. We want to - // fallback gracefully in this case. - - let file_text = r#" -fn main() { - struct Foo; - - impl !Sync for Foo {} - - unsafe impl Send for &'static Foo { - // error: cross-crate traits with a default impl, like `core::marker::Send`, - // can only be implemented for a struct/enum type, not - // `&'static Foo` -}"#; - - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - - let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1); - rbrace_span.lo = rbrace_span.hi; - - let mut snippet = SnippetData::new(cm.clone(), Some(rbrace_span)); - snippet.push(rbrace_span, false, None); - let lines = snippet.render_lines(); - let text: String = make_string(&lines); - println!("r#\"\n{}\"", text); - assert_eq!(text, &r#" - --> foo.rs:11:2 - |> -11 |> } - |> - -"#[1..]); -} diff --git a/syntex_syntax/src/ext/base.rs b/syntex_syntax/src/ext/base.rs index 5da81a26..ca38ef06 100644 --- a/syntex_syntax/src/ext/base.rs +++ b/syntex_syntax/src/ext/base.rs @@ -12,8 +12,9 @@ pub use self::SyntaxExtension::*; use ast; use ast::{Name, PatKind}; -use codemap; -use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION}; +use attr::HasAttrs; +use codemap::{self, CodeMap, ExpnInfo}; +use syntax_pos::{Span, ExpnId, NO_EXPANSION}; use errors::DiagnosticBuilder; use ext; use ext::expand; @@ -31,6 +32,7 @@ use fold::Folder; use std::collections::{HashMap, HashSet}; use std::rc::Rc; use std::default::Default; +use tokenstream; #[derive(Debug,Clone)] @@ -40,29 +42,31 @@ pub enum Annotatable { ImplItem(P), } -impl Annotatable { - pub fn attrs(&self) -> &[ast::Attribute] { +impl HasAttrs for Annotatable { + fn attrs(&self) -> &[ast::Attribute] { match *self { - Annotatable::Item(ref i) => &i.attrs, - Annotatable::TraitItem(ref ti) => &ti.attrs, - Annotatable::ImplItem(ref ii) => &ii.attrs, + Annotatable::Item(ref item) => &item.attrs, + Annotatable::TraitItem(ref trait_item) => &trait_item.attrs, + Annotatable::ImplItem(ref impl_item) => &impl_item.attrs, } } - pub fn fold_attrs(self, attrs: Vec) -> Annotatable { + fn map_attrs) -> Vec>(self, f: F) -> Self { match self { - Annotatable::Item(i) => Annotatable::Item(i.map(|i| ast::Item { - attrs: attrs, - ..i - })), - Annotatable::TraitItem(i) => Annotatable::TraitItem(i.map(|ti| { - ast::TraitItem { attrs: attrs, ..ti } - })), - Annotatable::ImplItem(i) => Annotatable::ImplItem(i.map(|ii| { - ast::ImplItem { attrs: attrs, ..ii } - })), + Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)), + Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)), + Annotatable::ImplItem(impl_item) => Annotatable::ImplItem(impl_item.map_attrs(f)), } } +} + +impl Annotatable { + pub fn attrs(&self) -> &[ast::Attribute] { + HasAttrs::attrs(self) + } + pub fn fold_attrs(self, attrs: Vec) -> Annotatable { + self.map_attrs(|_| attrs) + } pub fn expect_item(self) -> P { match self { @@ -129,9 +133,7 @@ impl MultiItemDecorator for F } } -// A more flexible ItemKind::Modifier (ItemKind::Modifier should go away, eventually, FIXME). -// meta_item is the annotation, item is the item being modified, parent_item -// is the impl or trait item is declared in if item is part of such a thing. +// `meta_item` is the annotation, and `item` is the item being modified. // FIXME Decorators should follow the same pattern too. pub trait MultiItemModifier { fn expand(&self, @@ -139,22 +141,26 @@ pub trait MultiItemModifier { span: Span, meta_item: &ast::MetaItem, item: Annotatable) - -> Annotatable; + -> Vec; } -impl MultiItemModifier for F - where F: Fn(&mut ExtCtxt, - Span, - &ast::MetaItem, - Annotatable) -> Annotatable +impl MultiItemModifier for F + where F: Fn(&mut ExtCtxt, Span, &ast::MetaItem, Annotatable) -> T, + T: Into>, { fn expand(&self, ecx: &mut ExtCtxt, span: Span, meta_item: &ast::MetaItem, item: Annotatable) - -> Annotatable { - (*self)(ecx, span, meta_item, item) + -> Vec { + (*self)(ecx, span, meta_item, item).into() + } +} + +impl Into> for Annotatable { + fn into(self) -> Vec { + vec![self] } } @@ -163,20 +169,22 @@ pub trait TTMacroExpander { fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, - token_tree: &[ast::TokenTree]) + token_tree: &[tokenstream::TokenTree]) -> Box; } pub type MacroExpanderFn = - for<'cx> fn(&'cx mut ExtCtxt, Span, &[ast::TokenTree]) -> Box; + for<'cx> fn(&'cx mut ExtCtxt, Span, &[tokenstream::TokenTree]) + -> Box; impl TTMacroExpander for F - where F : for<'cx> Fn(&'cx mut ExtCtxt, Span, &[ast::TokenTree]) -> Box + where F : for<'cx> Fn(&'cx mut ExtCtxt, Span, &[tokenstream::TokenTree]) + -> Box { fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, - token_tree: &[ast::TokenTree]) + token_tree: &[tokenstream::TokenTree]) -> Box { (*self)(ecx, span, token_tree) } @@ -187,22 +195,23 @@ pub trait IdentMacroExpander { cx: &'cx mut ExtCtxt, sp: Span, ident: ast::Ident, - token_tree: Vec ) + token_tree: Vec ) -> Box; } pub type IdentMacroExpanderFn = - for<'cx> fn(&'cx mut ExtCtxt, Span, ast::Ident, Vec) -> Box; + for<'cx> fn(&'cx mut ExtCtxt, Span, ast::Ident, Vec) + -> Box; impl IdentMacroExpander for F where F : for<'cx> Fn(&'cx mut ExtCtxt, Span, ast::Ident, - Vec) -> Box + Vec) -> Box { fn expand<'cx>(&self, cx: &'cx mut ExtCtxt, sp: Span, ident: ast::Ident, - token_tree: Vec ) + token_tree: Vec ) -> Box { (*self)(cx, sp, ident, token_tree) @@ -212,10 +221,11 @@ impl IdentMacroExpander for F // Use a macro because forwarding to a simple function has type system issues macro_rules! make_stmts_default { ($me:expr) => { - $me.make_expr().map(|e| { - SmallVector::one(codemap::respan( - e.span, ast::StmtKind::Expr(e, ast::DUMMY_NODE_ID))) - }) + $me.make_expr().map(|e| SmallVector::one(ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: e.span, + node: ast::StmtKind::Expr(e), + })) } } @@ -236,6 +246,11 @@ pub trait MacResult { None } + /// Create zero or more trait items. + fn make_trait_items(self: Box) -> Option> { + None + } + /// Create a pattern. fn make_pat(self: Box) -> Option> { None @@ -283,6 +298,7 @@ make_MacEager! { pat: P, items: SmallVector>, impl_items: SmallVector, + trait_items: SmallVector, stmts: SmallVector, ty: P, } @@ -300,6 +316,10 @@ impl MacResult for MacEager { self.impl_items } + fn make_trait_items(self: Box) -> Option> { + self.trait_items + } + fn make_stmts(self: Box) -> Option> { match self.stmts.as_ref().map_or(0, |s| s.len()) { 0 => make_stmts_default!(self), @@ -360,7 +380,7 @@ impl DummyResult { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(codemap::respan(sp, ast::LitKind::Bool(false)))), span: sp, - attrs: None, + attrs: ast::ThinVec::new(), }) } @@ -408,11 +428,24 @@ impl MacResult for DummyResult { } } + fn make_trait_items(self: Box) -> Option> { + if self.expr_only { + None + } else { + Some(SmallVector::zero()) + } + } + fn make_stmts(self: Box) -> Option> { - Some(SmallVector::one( - codemap::respan(self.span, - ast::StmtKind::Expr(DummyResult::raw_expr(self.span), - ast::DUMMY_NODE_ID)))) + Some(SmallVector::one(ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Expr(DummyResult::raw_expr(self.span)), + span: self.span, + })) + } + + fn make_ty(self: Box) -> Option> { + Some(DummyResult::raw_ty(self.span)) } } @@ -607,7 +640,7 @@ impl<'a> ExtCtxt<'a> { expand::MacroExpander::new(self) } - pub fn new_parser_from_tts(&self, tts: &[ast::TokenTree]) + pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) -> parser::Parser<'a> { parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg()) } @@ -806,7 +839,7 @@ pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) /// done as rarely as possible). pub fn check_zero_tts(cx: &ExtCtxt, sp: Span, - tts: &[ast::TokenTree], + tts: &[tokenstream::TokenTree], name: &str) { if !tts.is_empty() { cx.span_err(sp, &format!("{} takes no arguments", name)); @@ -817,7 +850,7 @@ pub fn check_zero_tts(cx: &ExtCtxt, /// is not a string literal, emit an error and return None. pub fn get_single_str_from_tts(cx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree], + tts: &[tokenstream::TokenTree], name: &str) -> Option { let mut p = cx.new_parser_from_tts(tts); @@ -838,7 +871,7 @@ pub fn get_single_str_from_tts(cx: &mut ExtCtxt, /// parsing error, emit a non-fatal error and return None. pub fn get_exprs_from_tts(cx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> Option>> { + tts: &[tokenstream::TokenTree]) -> Option>> { let mut p = cx.new_parser_from_tts(tts); let mut es = Vec::new(); while p.token != token::Eof { diff --git a/syntex_syntax/src/ext/build.rs b/syntex_syntax/src/ext/build.rs index 3a1cdae9..435241f4 100644 --- a/syntex_syntax/src/ext/build.rs +++ b/syntex_syntax/src/ext/build.rs @@ -11,7 +11,8 @@ use abi::Abi; use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind}; use attr; -use codemap::{Span, respan, Spanned, DUMMY_SP, Pos}; +use syntax_pos::{Span, DUMMY_SP, Pos}; +use codemap::{respan, Spanned}; use ext::base::ExtCtxt; use parse::token::{self, keywords, InternedString}; use ptr::P; @@ -87,6 +88,7 @@ pub trait AstBuilder { // statements fn stmt_expr(&self, expr: P) -> ast::Stmt; + fn stmt_semi(&self, expr: P) -> ast::Stmt; fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, ex: P) -> ast::Stmt; fn stmt_let_typed(&self, sp: Span, @@ -98,12 +100,8 @@ pub trait AstBuilder { fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt; // blocks - fn block(&self, span: Span, stmts: Vec, - expr: Option>) -> P; + fn block(&self, span: Span, stmts: Vec) -> P; fn block_expr(&self, expr: P) -> P; - fn block_all(&self, span: Span, - stmts: Vec, - expr: Option>) -> P; // expressions fn expr(&self, span: Span, node: ast::ExprKind) -> P; @@ -508,7 +506,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn stmt_expr(&self, expr: P) -> ast::Stmt { - respan(expr.span, ast::StmtKind::Semi(expr, ast::DUMMY_NODE_ID)) + ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: expr.span, + node: ast::StmtKind::Expr(expr), + } + } + + fn stmt_semi(&self, expr: P) -> ast::Stmt { + ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: expr.span, + node: ast::StmtKind::Semi(expr), + } } fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, @@ -525,10 +535,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> { init: Some(ex), id: ast::DUMMY_NODE_ID, span: sp, - attrs: None, + attrs: ast::ThinVec::new(), }); - let decl = respan(sp, ast::DeclKind::Local(local)); - respan(sp, ast::StmtKind::Decl(P(decl), ast::DUMMY_NODE_ID)) + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Local(local), + span: sp, + } } fn stmt_let_typed(&self, @@ -550,36 +563,37 @@ impl<'a> AstBuilder for ExtCtxt<'a> { init: Some(ex), id: ast::DUMMY_NODE_ID, span: sp, - attrs: None, + attrs: ast::ThinVec::new(), }); - let decl = respan(sp, ast::DeclKind::Local(local)); - P(respan(sp, ast::StmtKind::Decl(P(decl), ast::DUMMY_NODE_ID))) - } - - fn block(&self, span: Span, stmts: Vec, - expr: Option>) -> P { - self.block_all(span, stmts, expr) + P(ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Local(local), + span: sp, + }) } fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt { - let decl = respan(sp, ast::DeclKind::Item(item)); - respan(sp, ast::StmtKind::Decl(P(decl), ast::DUMMY_NODE_ID)) + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Item(item), + span: sp, + } } fn block_expr(&self, expr: P) -> P { - self.block_all(expr.span, Vec::new(), Some(expr)) - } - fn block_all(&self, - span: Span, - stmts: Vec, - expr: Option>) -> P { - P(ast::Block { - stmts: stmts, - expr: expr, - id: ast::DUMMY_NODE_ID, - rules: BlockCheckMode::Default, - span: span, - }) + self.block(expr.span, vec![ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: expr.span, + node: ast::StmtKind::Expr(expr), + }]) + } + fn block(&self, span: Span, stmts: Vec) -> P { + P(ast::Block { + stmts: stmts, + id: ast::DUMMY_NODE_ID, + rules: BlockCheckMode::Default, + span: span, + }) } fn expr(&self, span: Span, node: ast::ExprKind) -> P { @@ -587,7 +601,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, node: node, span: span, - attrs: None, + attrs: ast::ThinVec::new(), }) } @@ -830,7 +844,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec>) -> P { let pat = if subpats.is_empty() { - PatKind::Path(path) + PatKind::Path(None, path) } else { PatKind::TupleStruct(path, subpats, None) }; @@ -948,14 +962,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ids: Vec, stmts: Vec) -> P { - self.lambda(span, ids, self.block(span, stmts, None)) + self.lambda(span, ids, self.block(span, stmts)) } fn lambda_stmts_0(&self, span: Span, stmts: Vec) -> P { - self.lambda0(span, self.block(span, stmts, None)) + self.lambda0(span, self.block(span, stmts)) } fn lambda_stmts_1(&self, span: Span, stmts: Vec, ident: ast::Ident) -> P { - self.lambda1(span, self.block(span, stmts, None), ident) + self.lambda1(span, self.block(span, stmts), ident) } fn arg(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Arg { diff --git a/syntex_syntax/src/ext/expand.rs b/syntex_syntax/src/ext/expand.rs index d6341156..c670283e 100644 --- a/syntex_syntax/src/ext/expand.rs +++ b/syntex_syntax/src/ext/expand.rs @@ -8,17 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{Block, Crate, DeclKind, PatKind}; +use ast::{Block, Crate, PatKind}; use ast::{Local, Ident, Mac_, Name, SpannedIdent}; use ast::{MacStmtStyle, Mrk, Stmt, StmtKind, ItemKind}; -use ast::TokenTree; use ast; +use attr::HasAttrs; use ext::mtwt; -use ext::build::AstBuilder; use attr; -use attr::{AttrMetaMethods, WithAttrs, ThinAttributesExt}; -use codemap; -use codemap::{Span, Spanned, ExpnInfo, ExpnId, NameAndSpan, MacroBang, MacroAttribute}; +use attr::AttrMetaMethods; +use codemap::{Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; +use syntax_pos::{self, Span, ExpnId}; use config::StripUnconfigured; use ext::base::*; use feature_gate::{self, Features}; @@ -27,6 +26,7 @@ use fold::*; use util::move_map::MoveMap; use parse::token::{fresh_mark, fresh_name, intern, keywords}; use ptr::P; +use tokenstream::TokenTree; use util::small_vector::SmallVector; use visit; use visit::Visitor; @@ -41,20 +41,21 @@ trait MacroGenerable: Sized { // Fold this node or list of nodes using the given folder. fn fold_with(self, folder: &mut F) -> Self; - fn visit_with<'v, V: Visitor<'v>>(&'v self, visitor: &mut V); - - // Return a placeholder expansion to allow compilation to continue after an erroring expansion. - fn dummy(span: Span) -> Self; + fn visit_with(&self, visitor: &mut V); // The user-friendly name of the node type (e.g. "expression", "item", etc.) for diagnostics. fn kind_name() -> &'static str; + + // Return a placeholder expansion to allow compilation to continue after an erroring expansion. + fn dummy(span: Span) -> Self { + Self::make_with(DummyResult::any(span)).unwrap() + } } macro_rules! impl_macro_generable { ($($ty:ty: $kind_name:expr, .$make:ident, $(.$fold:ident)* $(lift .$fold_elt:ident)*, - $(.$visit:ident)* $(lift .$visit_elt:ident)*, - |$span:ident| $dummy:expr;)*) => { $( + $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { $( impl MacroGenerable for $ty { fn kind_name() -> &'static str { $kind_name } fn make_with<'a>(result: Box) -> Option { result.$make() } @@ -62,56 +63,51 @@ macro_rules! impl_macro_generable { $( folder.$fold(self) )* $( self.into_iter().flat_map(|item| folder. $fold_elt (item)).collect() )* } - fn visit_with<'v, V: Visitor<'v>>(&'v self, visitor: &mut V) { + fn visit_with(&self, visitor: &mut V) { $( visitor.$visit(self) )* $( for item in self.as_slice() { visitor. $visit_elt (item) } )* } - fn dummy($span: Span) -> Self { $dummy } } )* } } impl_macro_generable! { - P: "pattern", .make_pat, .fold_pat, .visit_pat, |span| P(DummyResult::raw_pat(span)); - P: "type", .make_ty, .fold_ty, .visit_ty, |span| DummyResult::raw_ty(span); - P: - "expression", .make_expr, .fold_expr, .visit_expr, |span| DummyResult::raw_expr(span); - SmallVector: - "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt, |_span| SmallVector::zero(); - SmallVector>: - "item", .make_items, lift .fold_item, lift .visit_item, |_span| SmallVector::zero(); + P: "expression", .make_expr, .fold_expr, .visit_expr; + P: "pattern", .make_pat, .fold_pat, .visit_pat; + P: "type", .make_ty, .fold_ty, .visit_ty; + SmallVector: "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt; + SmallVector>: "item", .make_items, lift .fold_item, lift .visit_item; + SmallVector: + "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item; SmallVector: - "impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item, - |_span| SmallVector::zero(); + "impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item; } impl MacroGenerable for Option> { fn kind_name() -> &'static str { "expression" } - fn dummy(_span: Span) -> Self { None } fn make_with<'a>(result: Box) -> Option { result.make_expr().map(Some) } fn fold_with(self, folder: &mut F) -> Self { self.and_then(|expr| folder.fold_opt_expr(expr)) } - fn visit_with<'v, V: Visitor<'v>>(&'v self, visitor: &mut V) { + fn visit_with(&self, visitor: &mut V) { self.as_ref().map(|expr| visitor.visit_expr(expr)); } } -pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P { +pub fn expand_expr(mut expr: ast::Expr, fld: &mut MacroExpander) -> P { match expr.node { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. ast::ExprKind::Mac(mac) => { - expand_mac_invoc(mac, None, expr.attrs.into_attr_vec(), expr.span, fld) + return expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, fld); } ast::ExprKind::While(cond, body, opt_ident) => { let cond = fld.fold_expr(cond); let (body, opt_ident) = expand_loop_block(body, opt_ident, fld); - fld.cx.expr(expr.span, ast::ExprKind::While(cond, body, opt_ident)) - .with_attrs(fold_thin_attrs(expr.attrs, fld)) + expr.node = ast::ExprKind::While(cond, body, opt_ident); } ast::ExprKind::WhileLet(pat, cond, body, opt_ident) => { @@ -128,14 +124,12 @@ pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P { }); assert!(rewritten_pats.len() == 1); - let wl = ast::ExprKind::WhileLet(rewritten_pats.remove(0), cond, body, opt_ident); - fld.cx.expr(expr.span, wl).with_attrs(fold_thin_attrs(expr.attrs, fld)) + expr.node = ast::ExprKind::WhileLet(rewritten_pats.remove(0), cond, body, opt_ident); } ast::ExprKind::Loop(loop_block, opt_ident) => { let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld); - fld.cx.expr(expr.span, ast::ExprKind::Loop(loop_block, opt_ident)) - .with_attrs(fold_thin_attrs(expr.attrs, fld)) + expr.node = ast::ExprKind::Loop(loop_block, opt_ident); } ast::ExprKind::ForLoop(pat, head, body, opt_ident) => { @@ -152,8 +146,7 @@ pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P { assert!(rewritten_pats.len() == 1); let head = fld.fold_expr(head); - let fl = ast::ExprKind::ForLoop(rewritten_pats.remove(0), head, body, opt_ident); - fld.cx.expr(expr.span, fl).with_attrs(fold_thin_attrs(expr.attrs, fld)) + expr.node = ast::ExprKind::ForLoop(rewritten_pats.remove(0), head, body, opt_ident); } ast::ExprKind::IfLet(pat, sub_expr, body, else_opt) => { @@ -171,25 +164,21 @@ pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P { let else_opt = else_opt.map(|else_opt| fld.fold_expr(else_opt)); let sub_expr = fld.fold_expr(sub_expr); - let il = ast::ExprKind::IfLet(rewritten_pats.remove(0), sub_expr, body, else_opt); - fld.cx.expr(expr.span, il).with_attrs(fold_thin_attrs(expr.attrs, fld)) + expr.node = ast::ExprKind::IfLet(rewritten_pats.remove(0), sub_expr, body, else_opt); } ast::ExprKind::Closure(capture_clause, fn_decl, block, fn_decl_span) => { let (rewritten_fn_decl, rewritten_block) = expand_and_rename_fn_decl_and_block(fn_decl, block, fld); - let new_node = ast::ExprKind::Closure(capture_clause, - rewritten_fn_decl, - rewritten_block, - fn_decl_span); - P(ast::Expr{ id: expr.id, - node: new_node, - span: expr.span, - attrs: fold_thin_attrs(expr.attrs, fld) }) + expr.node = ast::ExprKind::Closure(capture_clause, + rewritten_fn_decl, + rewritten_block, + fn_decl_span); } - _ => P(noop_fold_expr(expr, fld)), - } + _ => expr = noop_fold_expr(expr, fld), + }; + P(expr) } /// Expand a macro invocation. Returns the result of expansion. @@ -213,7 +202,7 @@ fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec 1 { + if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() { fld.cx.span_err(path.span, "expected macro name without module separators"); return None; } @@ -248,7 +237,7 @@ fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec(mac: ast::Mac, ident: Option, attrs: Vec SmallVector { }; let (mac, style, attrs) = match stmt.node { - StmtKind::Mac(mac, style, attrs) => (mac, style, attrs), + StmtKind::Mac(mac) => mac.unwrap(), _ => return expand_non_macro_stmt(stmt, fld) }; let mut fully_expanded: SmallVector = - expand_mac_invoc(mac.unwrap(), None, attrs.into_attr_vec(), stmt.span, fld); + expand_mac_invoc(mac, None, attrs.into(), stmt.span, fld); // If this is a macro invocation with a semicolon, then apply that // semicolon to the final statement produced by expansion. if style == MacStmtStyle::Semicolon { if let Some(stmt) = fully_expanded.pop() { - let new_stmt = Spanned { + fully_expanded.push(Stmt { + id: stmt.id, node: match stmt.node { - StmtKind::Expr(e, stmt_id) => StmtKind::Semi(e, stmt_id), + StmtKind::Expr(expr) => StmtKind::Semi(expr), _ => stmt.node /* might already have a semi */ }, - span: stmt.span - }; - fully_expanded.push(new_stmt); + span: stmt.span, + }); } } @@ -471,73 +460,53 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector { // expand a non-macro stmt. this is essentially the fallthrough for // expand_stmt, above. -fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroExpander) +fn expand_non_macro_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector { // is it a let? - match node { - StmtKind::Decl(decl, node_id) => decl.and_then(|Spanned {node: decl, span}| match decl { - DeclKind::Local(local) => { - // take it apart: - let rewritten_local = local.map(|Local {id, pat, ty, init, span, attrs}| { - // expand the ty since TyKind::FixedLengthVec contains an Expr - // and thus may have a macro use - let expanded_ty = ty.map(|t| fld.fold_ty(t)); - // expand the pat (it might contain macro uses): - let expanded_pat = fld.fold_pat(pat); - // find the PatIdents in the pattern: - // oh dear heaven... this is going to include the enum - // names, as well... but that should be okay, as long as - // the new names are gensyms for the old ones. - // generate fresh names, push them to a new pending list - let idents = pattern_bindings(&expanded_pat); - let mut new_pending_renames = - idents.iter().map(|ident| (*ident, fresh_name(*ident))).collect(); - // rewrite the pattern using the new names (the old - // ones have already been applied): - let rewritten_pat = { - // nested binding to allow borrow to expire: - let mut rename_fld = IdentRenamer{renames: &mut new_pending_renames}; - rename_fld.fold_pat(expanded_pat) - }; - // add them to the existing pending renames: - fld.cx.syntax_env.info().pending_renames - .extend(new_pending_renames); - Local { - id: id, - ty: expanded_ty, - pat: rewritten_pat, - // also, don't forget to expand the init: - init: init.map(|e| fld.fold_expr(e)), - span: span, - attrs: fold::fold_thin_attrs(attrs, fld), - } - }); - SmallVector::one(Spanned { - node: StmtKind::Decl(P(Spanned { - node: DeclKind::Local(rewritten_local), - span: span - }), - node_id), - span: stmt_span - }) - } - _ => { - noop_fold_stmt(Spanned { - node: StmtKind::Decl(P(Spanned { - node: decl, - span: span - }), - node_id), - span: stmt_span - }, fld) - } - }), - _ => { - noop_fold_stmt(Spanned { - node: node, - span: stmt_span - }, fld) + match stmt.node { + StmtKind::Local(local) => { + // take it apart: + let rewritten_local = local.map(|Local {id, pat, ty, init, span, attrs}| { + // expand the ty since TyKind::FixedLengthVec contains an Expr + // and thus may have a macro use + let expanded_ty = ty.map(|t| fld.fold_ty(t)); + // expand the pat (it might contain macro uses): + let expanded_pat = fld.fold_pat(pat); + // find the PatIdents in the pattern: + // oh dear heaven... this is going to include the enum + // names, as well... but that should be okay, as long as + // the new names are gensyms for the old ones. + // generate fresh names, push them to a new pending list + let idents = pattern_bindings(&expanded_pat); + let mut new_pending_renames = + idents.iter().map(|ident| (*ident, fresh_name(*ident))).collect(); + // rewrite the pattern using the new names (the old + // ones have already been applied): + let rewritten_pat = { + // nested binding to allow borrow to expire: + let mut rename_fld = IdentRenamer{renames: &mut new_pending_renames}; + rename_fld.fold_pat(expanded_pat) + }; + // add them to the existing pending renames: + fld.cx.syntax_env.info().pending_renames + .extend(new_pending_renames); + Local { + id: id, + ty: expanded_ty, + pat: rewritten_pat, + // also, don't forget to expand the init: + init: init.map(|e| fld.fold_expr(e)), + span: span, + attrs: fold::fold_thin_attrs(attrs, fld), + } + }); + SmallVector::one(Stmt { + id: stmt.id, + node: StmtKind::Local(rewritten_local), + span: stmt.span, + }) } + _ => noop_fold_stmt(stmt, fld), } } @@ -595,7 +564,7 @@ struct PatIdentFinder { ident_accumulator: Vec } -impl<'v> Visitor<'v> for PatIdentFinder { +impl Visitor for PatIdentFinder { fn visit_pat(&mut self, pattern: &ast::Pat) { match *pattern { ast::Pat { id: _, node: PatKind::Ident(_, ref path1, ref inner), span: _ } => { @@ -636,23 +605,14 @@ pub fn expand_block(blk: P, fld: &mut MacroExpander) -> P { // expand the elements of a block. pub fn expand_block_elts(b: P, fld: &mut MacroExpander) -> P { - b.map(|Block {id, stmts, expr, rules, span}| { + b.map(|Block {id, stmts, rules, span}| { let new_stmts = stmts.into_iter().flat_map(|x| { // perform pending renames and expand macros in the statement fld.fold_stmt(x).into_iter() }).collect(); - let new_expr = expr.map(|x| { - let expr = { - let pending_renames = &mut fld.cx.syntax_env.info().pending_renames; - let mut rename_fld = IdentRenamer{renames:pending_renames}; - rename_fld.fold_expr(x) - }; - fld.fold_expr(expr) - }); Block { id: fld.new_id(id), stmts: new_stmts, - expr: new_expr, rules: rules, span: span } @@ -681,7 +641,7 @@ pub struct IdentRenamer<'a> { impl<'a> Folder for IdentRenamer<'a> { fn fold_ident(&mut self, id: Ident) -> Ident { - Ident::new(id.name, mtwt::apply_renames(self.renames, id.ctxt)) + mtwt::apply_renames(self.renames, id) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { fold::noop_fold_mac(mac, self) @@ -705,8 +665,7 @@ impl<'a> Folder for PatIdentRenamer<'a> { pat.map(|ast::Pat {id, node, span}| match node { PatKind::Ident(binding_mode, Spanned{span: sp, node: ident}, sub) => { - let new_ident = Ident::new(ident.name, - mtwt::apply_renames(self.renames, ident.ctxt)); + let new_ident = mtwt::apply_renames(self.renames, ident); let new_node = PatKind::Ident(binding_mode, Spanned{span: sp, node: new_ident}, @@ -725,12 +684,8 @@ impl<'a> Folder for PatIdentRenamer<'a> { } } -fn expand_annotatable(a: Annotatable, - fld: &mut MacroExpander) - -> SmallVector { - let a = expand_item_multi_modifier(a, fld); - - let new_items: SmallVector = match a { +fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector { + match a { Annotatable::Item(it) => match it.node { ast::ItemKind::Mac(..) => { it.and_then(|it| match it.node { @@ -758,153 +713,65 @@ fn expand_annotatable(a: Annotatable, _ => noop_fold_item(it, fld), }.into_iter().map(|i| Annotatable::Item(i)).collect(), - Annotatable::TraitItem(it) => match it.node { - ast::TraitItemKind::Method(_, Some(_)) => { - let ti = it.unwrap(); - SmallVector::one(ast::TraitItem { - id: ti.id, - ident: ti.ident, - attrs: ti.attrs, - node: match ti.node { - ast::TraitItemKind::Method(sig, Some(body)) => { - let (sig, body) = expand_and_rename_method(sig, body, fld); - ast::TraitItemKind::Method(sig, Some(body)) - } - _ => unreachable!() - }, - span: ti.span, - }) - } - _ => fold::noop_fold_trait_item(it.unwrap(), fld) - }.into_iter().map(|ti| Annotatable::TraitItem(P(ti))).collect(), + Annotatable::TraitItem(it) => { + expand_trait_item(it.unwrap(), fld).into_iter(). + map(|it| Annotatable::TraitItem(P(it))).collect() + } Annotatable::ImplItem(ii) => { expand_impl_item(ii.unwrap(), fld).into_iter(). map(|ii| Annotatable::ImplItem(P(ii))).collect() } - }; - - new_items.into_iter().flat_map(|a| decorate(a, fld)).collect() -} - -fn decorate(a: Annotatable, fld: &mut MacroExpander) -> SmallVector { - let mut decorator_items = SmallVector::zero(); - let mut new_attrs = Vec::new(); - expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs); - - let mut new_items = SmallVector::one(a.fold_attrs(new_attrs)); - new_items.push_all(decorator_items); - new_items -} - -// Partition a set of attributes into one kind of attribute, and other kinds. -macro_rules! partition { - ($fn_name: ident, $variant: ident) => { - #[allow(deprecated)] // The `allow` is needed because the `Modifier` variant might be used. - fn $fn_name(attrs: &[ast::Attribute], - fld: &MacroExpander) - -> (Vec, Vec) { - attrs.iter().cloned().partition(|attr| { - match fld.cx.syntax_env.find(intern(&attr.name())) { - Some(rc) => match *rc { - $variant(..) => true, - _ => false - }, - _ => false - } - }) - } } } -partition!(multi_modifiers, MultiModifier); - - -fn expand_decorators(a: Annotatable, - fld: &mut MacroExpander, - decorator_items: &mut SmallVector, - new_attrs: &mut Vec) -{ - for attr in a.attrs() { - let mname = intern(&attr.name()); - match fld.cx.syntax_env.find(mname) { - Some(rc) => match *rc { - MultiDecorator(ref dec) => { - attr::mark_used(&attr); - - fld.cx.bt_push(ExpnInfo { - call_site: attr.span, - callee: NameAndSpan { - format: MacroAttribute(mname), - span: Some(attr.span), - // attributes can do whatever they like, - // for now. - allow_internal_unstable: true, - } - }); - - let mut items: SmallVector = SmallVector::zero(); - dec.expand(fld.cx, - attr.span, - &attr.node.value, - &a, - &mut |ann| items.push(ann)); - - for item in items { - for configured_item in item.fold_with(&mut fld.strip_unconfigured()) { - decorator_items.extend(expand_annotatable(configured_item, fld)); - } +fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVector { + let mut multi_modifier = None; + item = item.map_attrs(|mut attrs| { + for i in 0..attrs.len() { + if let Some(extension) = fld.cx.syntax_env.find(intern(&attrs[i].name())) { + match *extension { + MultiModifier(..) | MultiDecorator(..) => { + multi_modifier = Some((attrs.remove(i), extension)); + break; } - - fld.cx.bt_pop(); + _ => {} } - _ => new_attrs.push((*attr).clone()), - }, - _ => new_attrs.push((*attr).clone()), + } } - } -} + attrs + }); -fn expand_item_multi_modifier(mut it: Annotatable, - fld: &mut MacroExpander) - -> Annotatable { - let (modifiers, other_attrs) = multi_modifiers(it.attrs(), fld); - - // Update the attrs, leave everything else alone. Is this mutation really a good idea? - it = it.fold_attrs(other_attrs); - - if modifiers.is_empty() { - return it - } - - for attr in &modifiers { - let mname = intern(&attr.name()); - - match fld.cx.syntax_env.find(mname) { - Some(rc) => match *rc { - MultiModifier(ref mac) => { - attr::mark_used(attr); - fld.cx.bt_push(ExpnInfo { - call_site: attr.span, - callee: NameAndSpan { - format: MacroAttribute(mname), - span: Some(attr.span), - // attributes can do whatever they like, - // for now - allow_internal_unstable: true, - } - }); - it = mac.expand(fld.cx, attr.span, &attr.node.value, it); - fld.cx.bt_pop(); + match multi_modifier { + None => expand_multi_modified(item, fld), + Some((attr, extension)) => { + attr::mark_used(&attr); + fld.cx.bt_push(ExpnInfo { + call_site: attr.span, + callee: NameAndSpan { + format: MacroAttribute(intern(&attr.name())), + span: Some(attr.span), + // attributes can do whatever they like, for now + allow_internal_unstable: true, } - _ => unreachable!() - }, - _ => unreachable!() + }); + + let modified = match *extension { + MultiModifier(ref mac) => mac.expand(fld.cx, attr.span, &attr.node.value, item), + MultiDecorator(ref mac) => { + let mut items = Vec::new(); + mac.expand(fld.cx, attr.span, &attr.node.value, &item, + &mut |item| items.push(item)); + items.push(item); + items + } + _ => unreachable!(), + }; + + fld.cx.bt_pop(); + modified.into_iter().flat_map(|it| expand_annotatable(it, fld)).collect() } } - - // Expansion may have added new ItemKind::Modifiers. - expand_item_multi_modifier(it, fld) } fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander) @@ -932,6 +799,31 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander) } } +fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander) + -> SmallVector { + match ti.node { + ast::TraitItemKind::Method(_, Some(_)) => { + SmallVector::one(ast::TraitItem { + id: ti.id, + ident: ti.ident, + attrs: ti.attrs, + node: match ti.node { + ast::TraitItemKind::Method(sig, Some(body)) => { + let (sig, body) = expand_and_rename_method(sig, body, fld); + ast::TraitItemKind::Method(sig, Some(body)) + } + _ => unreachable!() + }, + span: ti.span, + }) + } + ast::TraitItemKind::Macro(mac) => { + expand_mac_invoc(mac, None, ti.attrs, ti.span, fld) + } + _ => fold::noop_fold_trait_item(ti, fld) + } +} + /// Given a fn_decl and a block and a MacroExpander, expand the fn_decl, then use the /// PatIdents in its arguments to perform renaming in the FnDecl and /// the block, returning both the new FnDecl and the new Block. @@ -1012,9 +904,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { at_crate_root: bool, } - impl<'a, 'b, 'v> Visitor<'v> for MacroLoadingVisitor<'a, 'b> { - fn visit_mac(&mut self, _: &'v ast::Mac) {} - fn visit_item(&mut self, item: &'v ast::Item) { + impl<'a, 'b> Visitor for MacroLoadingVisitor<'a, 'b> { + fn visit_mac(&mut self, _: &ast::Mac) {} + fn visit_item(&mut self, item: &ast::Item) { if let ast::ItemKind::ExternCrate(..) = item.node { // We need to error on `#[macro_use] extern crate` when it isn't at the // crate root, because `$crate` won't work properly. @@ -1027,7 +919,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.at_crate_root = at_crate_root; } } - fn visit_block(&mut self, block: &'v ast::Block) { + fn visit_block(&mut self, block: &ast::Block) { let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false); visit::walk_block(self, block); self.at_crate_root = at_crate_root; @@ -1054,7 +946,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { fn fold_opt_expr(&mut self, expr: P) -> Option> { expr.and_then(|expr| match expr.node { ast::ExprKind::Mac(mac) => - expand_mac_invoc(mac, None, expr.attrs.into_attr_vec(), expr.span, self), + expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, self), _ => Some(expand_expr(expr, self)), }) } @@ -1072,7 +964,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { result = expand_item(item, self); self.pop_mod_path(); } else { - let filename = if inner != codemap::DUMMY_SP { + let filename = if inner != syntax_pos::DUMMY_SP { Some(self.cx.parse_sess.codemap().span_to_filename(inner)) } else { None }; let orig_filename = replace(&mut self.cx.filename, filename); @@ -1234,8 +1126,7 @@ impl Folder for Marker { Spanned { node: Mac_ { path: self.fold_path(node.path), - tts: self.fold_tts(&node.tts), - ctxt: mtwt::apply_mark(self.mark, node.ctxt), + tts: self.fold_tts(node.tts), }, span: self.new_span(span), } @@ -1250,7 +1141,7 @@ impl Folder for Marker { } // apply a given mark to the given token trees. Used prior to expansion of a macro. -fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec { +fn mark_tts(tts: Vec, m: Mrk) -> Vec { noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None}) } @@ -1261,12 +1152,12 @@ mod tests { use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig}; use ast; use ast::Name; - use codemap; + use syntax_pos; use ext::base::{ExtCtxt, DummyMacroLoader}; use ext::mtwt; use fold::Folder; use parse; - use parse::token::{self, keywords}; + use parse::token; use util::parser_testing::{string_to_parser}; use util::parser_testing::{string_to_pat, string_to_crate, strs_to_idents}; use visit; @@ -1280,7 +1171,7 @@ mod tests { path_accumulator: Vec , } - impl<'v> Visitor<'v> for PathExprFinderContext { + impl Visitor for PathExprFinderContext { fn visit_expr(&mut self, expr: &ast::Expr) { if let ast::ExprKind::Path(None, ref p) = expr.node { self.path_accumulator.push(p.clone()); @@ -1302,8 +1193,8 @@ mod tests { ident_accumulator: Vec } - impl<'v> Visitor<'v> for IdentFinder { - fn visit_ident(&mut self, _: codemap::Span, id: ast::Ident){ + impl Visitor for IdentFinder { + fn visit_ident(&mut self, _: syntax_pos::Span, id: ast::Ident){ self.ident_accumulator.push(id); } } @@ -1396,267 +1287,10 @@ mod tests { ); } - // renaming tests expand a crate and then check that the bindings match - // the right varrefs. The specification of the test case includes the - // text of the crate, and also an array of arrays. Each element in the - // outer array corresponds to a binding in the traversal of the AST - // induced by visit. Each of these arrays contains a list of indexes, - // interpreted as the varrefs in the varref traversal that this binding - // should match. So, for instance, in a program with two bindings and - // three varrefs, the array [[1, 2], [0]] would indicate that the first - // binding should match the second two varrefs, and the second binding - // should match the first varref. - // - // Put differently; this is a sparse representation of a boolean matrix - // indicating which bindings capture which identifiers. - // - // Note also that this matrix is dependent on the implicit ordering of - // the bindings and the varrefs discovered by the name-finder and the path-finder. - // - // The comparisons are done post-mtwt-resolve, so we're comparing renamed - // names; differences in marks don't matter any more. - // - // oog... I also want tests that check "bound-identifier-=?". That is, - // not just "do these have the same name", but "do they have the same - // name *and* the same marks"? Understanding this is really pretty painful. - // in principle, you might want to control this boolean on a per-varref basis, - // but that would make things even harder to understand, and might not be - // necessary for thorough testing. - type RenamingTest = (&'static str, Vec>, bool); - - #[test] - fn automatic_renaming () { - let tests: Vec = - vec!(// b & c should get new names throughout, in the expr too: - ("fn a() -> i32 { let b = 13; let c = b; b+c }", - vec!(vec!(0,1),vec!(2)), false), - // both x's should be renamed (how is this causing a bug?) - ("fn main () {let x: i32 = 13;x;}", - vec!(vec!(0)), false), - // the use of b after the + should be renamed, the other one not: - ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> i32 { let b = 13; f!(b)}", - vec!(vec!(1)), false), - // the b before the plus should not be renamed (requires marks) - ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> i32 { f!(b)}", - vec!(vec!(1)), false), - // the marks going in and out of letty should cancel, allowing that $x to - // capture the one following the semicolon. - // this was an awesome test case, and caught a *lot* of bugs. - ("macro_rules! letty(($x:ident) => (let $x = 15;)); - macro_rules! user(($x:ident) => ({letty!($x); $x})); - fn main() -> i32 {user!(z)}", - vec!(vec!(0)), false) - ); - for (idx,s) in tests.iter().enumerate() { - run_renaming_test(s,idx); - } - } - - // no longer a fixme #8062: this test exposes a *potential* bug; our system does - // not behave exactly like MTWT, but a conversation with Matthew Flatt - // suggests that this can only occur in the presence of local-expand, which - // we have no plans to support. ... unless it's needed for item hygiene.... - #[ignore] - #[test] - fn issue_8062(){ - run_renaming_test( - &("fn main() {let hrcoo = 19; macro_rules! getx(()=>(hrcoo)); getx!();}", - vec!(vec!(0)), true), 0) - } - - // FIXME #6994: - // the z flows into and out of two macros (g & f) along one path, and one - // (just g) along the other, so the result of the whole thing should - // be "let z_123 = 3; z_123" - #[ignore] - #[test] - fn issue_6994(){ - run_renaming_test( - &("macro_rules! g (($x:ident) => - ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)})); - fn a(){g!(z)}", - vec!(vec!(0)),false), - 0) - } - - // match variable hygiene. Should expand into - // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}} - #[test] - fn issue_9384(){ - run_renaming_test( - &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}})); - fn z() {match 8 {x => bad_macro!(x)}}", - // NB: the third "binding" is the repeat of the second one. - vec!(vec!(1,3),vec!(0,2),vec!(0,2)), - true), - 0) - } - - // interpolated nodes weren't getting labeled. - // should expand into - // fn main(){let g1_1 = 13; g1_1}} - #[test] - fn pat_expand_issue_15221(){ - run_renaming_test( - &("macro_rules! inner ( ($e:pat ) => ($e)); - macro_rules! outer ( ($e:pat ) => (inner!($e))); - fn main() { let outer!(g) = 13; g;}", - vec!(vec!(0)), - true), - 0) - } - // create a really evil test case where a $x appears inside a binding of $x // but *shouldn't* bind because it was inserted by a different macro.... // can't write this test case until we have macro-generating macros. - // method arg hygiene - // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1} - #[test] - fn method_arg_hygiene(){ - run_renaming_test( - &("macro_rules! inject_x (()=>(x)); - macro_rules! inject_self (()=>(self)); - struct A; - impl A{fn get_x(&self, x: i32) {self + inject_self!() + inject_x!() + x;} }", - vec!(vec!(0),vec!(3)), - true), - 0) - } - - // ooh, got another bite? - // expands to struct A; impl A {fn thingy(&self_1) {self_1;}} - #[test] - fn method_arg_hygiene_2(){ - run_renaming_test( - &("struct A; - macro_rules! add_method (($T:ty) => - (impl $T { fn thingy(&self) {self;} })); - add_method!(A);", - vec!(vec!(0)), - true), - 0) - } - - // item fn hygiene - // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};} - #[test] - fn issue_9383(){ - run_renaming_test( - &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex })); - fn q(x: i32) { bad_macro!(x); }", - vec!(vec!(1),vec!(0)),true), - 0) - } - - // closure arg hygiene (ExprKind::Closure) - // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);} - #[test] - fn closure_arg_hygiene(){ - run_renaming_test( - &("macro_rules! inject_x (()=>(x)); - fn f(){(|x : i32| {(inject_x!() + x)})(3);}", - vec!(vec!(1)), - true), - 0) - } - - // macro_rules in method position. Sadly, unimplemented. - #[test] - fn macro_in_method_posn(){ - expand_crate_str( - "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13})); - struct A; - impl A{ my_method!(); } - fn f(){A.thirteen;}".to_string()); - } - - // another nested macro - // expands to impl Entries {fn size_hint(&self_1) {self_1;} - #[test] - fn item_macro_workaround(){ - run_renaming_test( - &("macro_rules! item { ($i:item) => {$i}} - struct Entries; - macro_rules! iterator_impl { - () => { item!( impl Entries { fn size_hint(&self) { self;}});}} - iterator_impl! { }", - vec!(vec!(0)), true), - 0) - } - - // run one of the renaming tests - fn run_renaming_test(t: &RenamingTest, test_idx: usize) { - let invalid_name = keywords::Invalid.name(); - let (teststr, bound_connections, bound_ident_check) = match *t { - (ref str,ref conns, bic) => (str.to_string(), conns.clone(), bic) - }; - let cr = expand_crate_str(teststr.to_string()); - let bindings = crate_bindings(&cr); - let varrefs = crate_varrefs(&cr); - - // must be one check clause for each binding: - assert_eq!(bindings.len(),bound_connections.len()); - for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() { - let binding_name = mtwt::resolve(bindings[binding_idx]); - let binding_marks = mtwt::marksof(bindings[binding_idx].ctxt, invalid_name); - // shouldmatch can't name varrefs that don't exist: - assert!((shouldmatch.is_empty()) || - (varrefs.len() > *shouldmatch.iter().max().unwrap())); - for (idx,varref) in varrefs.iter().enumerate() { - let print_hygiene_debug_info = || { - // good lord, you can't make a path with 0 segments, can you? - let final_varref_ident = match varref.segments.last() { - Some(pathsegment) => pathsegment.identifier, - None => panic!("varref with 0 path segments?") - }; - let varref_name = mtwt::resolve(final_varref_ident); - let varref_idents : Vec - = varref.segments.iter().map(|s| s.identifier) - .collect(); - println!("varref #{}: {:?}, resolves to {}",idx, varref_idents, varref_name); - println!("varref's first segment's string: \"{}\"", final_varref_ident); - println!("binding #{}: {}, resolves to {}", - binding_idx, bindings[binding_idx], binding_name); - mtwt::with_sctable(|x| mtwt::display_sctable(x)); - }; - if shouldmatch.contains(&idx) { - // it should be a path of length 1, and it should - // be free-identifier=? or bound-identifier=? to the given binding - assert_eq!(varref.segments.len(),1); - let varref_name = mtwt::resolve(varref.segments[0].identifier); - let varref_marks = mtwt::marksof(varref.segments[0] - .identifier - .ctxt, - invalid_name); - if !(varref_name==binding_name) { - println!("uh oh, should match but doesn't:"); - print_hygiene_debug_info(); - } - assert_eq!(varref_name,binding_name); - if bound_ident_check { - // we're checking bound-identifier=?, and the marks - // should be the same, too: - assert_eq!(varref_marks,binding_marks.clone()); - } - } else { - let varref_name = mtwt::resolve(varref.segments[0].identifier); - let fail = (varref.segments.len() == 1) - && (varref_name == binding_name); - // temp debugging: - if fail { - println!("failure on test {}",test_idx); - println!("text of test case: \"{}\"", teststr); - println!(""); - println!("uh oh, matches but shouldn't:"); - print_hygiene_debug_info(); - } - assert!(!fail); - } - } - } - } - #[test] fn fmt_in_macro_used_inside_module_macro() { let crate_str = "macro_rules! fmt_wrap(($b:expr)=>($b.to_string())); diff --git a/syntex_syntax/src/ext/mtwt.rs b/syntex_syntax/src/ext/mtwt.rs index 7ac0e8c6..c9e8715d 100644 --- a/syntex_syntax/src/ext/mtwt.rs +++ b/syntex_syntax/src/ext/mtwt.rs @@ -25,34 +25,22 @@ use std::collections::HashMap; /// The SCTable contains a table of SyntaxContext_'s. It /// represents a flattened tree structure, to avoid having /// managed pointers everywhere (that caused an ICE). -/// the mark_memo and rename_memo fields are side-tables +/// the `marks` and `renames` fields are side-tables /// that ensure that adding the same mark to the same context -/// gives you back the same context as before. This shouldn't -/// change the semantics--everything here is immutable--but -/// it should cut down on memory use *a lot*; applying a mark -/// to a tree containing 50 identifiers would otherwise generate -/// 50 new contexts +/// gives you back the same context as before. This should cut +/// down on memory use *a lot*; applying a mark to a tree containing +/// 50 identifiers would otherwise generate 50 new contexts. pub struct SCTable { table: RefCell>, - mark_memo: RefCell>, - // The pair (Name,SyntaxContext) is actually one Ident, but it needs to be hashed and - // compared as pair (name, ctxt) and not as an Ident - rename_memo: RefCell>, + marks: RefCell>, + renames: RefCell>, } #[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy, Clone)] pub enum SyntaxContext_ { EmptyCtxt, Mark (Mrk,SyntaxContext), - /// flattening the name and syntaxcontext into the rename... - /// HIDDEN INVARIANTS: - /// 1) the first name in a Rename node - /// can only be a programmer-supplied name. - /// 2) Every Rename node with a given Name in the - /// "to" slot must have the same name and context - /// in the "from" slot. In essence, they're all - /// pointers to a single "rename" event node. - Rename (Ident,Name,SyntaxContext), + Rename (Name), /// actually, IllegalCtxt may not be necessary. IllegalCtxt } @@ -67,37 +55,39 @@ pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext { /// Extend a syntax context with a given mark and sctable (explicit memoization) fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxContext { - let key = (ctxt, m); - *table.mark_memo.borrow_mut().entry(key).or_insert_with(|| { - SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt))) - }) + let ctxts = &mut *table.table.borrow_mut(); + match ctxts[ctxt.0 as usize] { + // Applying the same mark twice is a no-op. + Mark(outer_mark, prev_ctxt) if outer_mark == m => return prev_ctxt, + _ => *table.marks.borrow_mut().entry((ctxt, m)).or_insert_with(|| { + SyntaxContext(idx_push(ctxts, Mark(m, ctxt))) + }), + } } /// Extend a syntax context with a given rename -pub fn apply_rename(id: Ident, to:Name, - ctxt: SyntaxContext) -> SyntaxContext { - with_sctable(|table| apply_rename_internal(id, to, ctxt, table)) +pub fn apply_rename(from: Ident, to: Name, ident: Ident) -> Ident { + with_sctable(|table| apply_rename_internal(from, to, ident, table)) } /// Extend a syntax context with a given rename and sctable (explicit memoization) -fn apply_rename_internal(id: Ident, - to: Name, - ctxt: SyntaxContext, - table: &SCTable) -> SyntaxContext { - let key = (ctxt, (id.name, id.ctxt), to); - - *table.rename_memo.borrow_mut().entry(key).or_insert_with(|| { - SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt))) - }) +fn apply_rename_internal(from: Ident, to: Name, ident: Ident, table: &SCTable) -> Ident { + if (ident.name, ident.ctxt) != (from.name, from.ctxt) { + return ident; + } + let ctxt = *table.renames.borrow_mut().entry(to).or_insert_with(|| { + SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Rename(to))) + }); + Ident { ctxt: ctxt, ..ident } } /// Apply a list of renamings to a context // if these rename lists get long, it would make sense // to consider memoizing this fold. This may come up // when we add hygiene to item names. -pub fn apply_renames(renames: &RenameList, ctxt: SyntaxContext) -> SyntaxContext { - renames.iter().fold(ctxt, |ctxt, &(from, to)| { - apply_rename(from, to, ctxt) +pub fn apply_renames(renames: &RenameList, ident: Ident) -> Ident { + renames.iter().fold(ident, |ident, &(from, to)| { + apply_rename(from, to, ident) }) } @@ -114,8 +104,8 @@ pub fn with_sctable(op: F) -> T where fn new_sctable_internal() -> SCTable { SCTable { table: RefCell::new(vec!(EmptyCtxt, IllegalCtxt)), - mark_memo: RefCell::new(HashMap::new()), - rename_memo: RefCell::new(HashMap::new()), + marks: RefCell::new(HashMap::new()), + renames: RefCell::new(HashMap::new()), } } @@ -131,20 +121,18 @@ pub fn display_sctable(table: &SCTable) { pub fn clear_tables() { with_sctable(|table| { *table.table.borrow_mut() = Vec::new(); - *table.mark_memo.borrow_mut() = HashMap::new(); - *table.rename_memo.borrow_mut() = HashMap::new(); + *table.marks.borrow_mut() = HashMap::new(); + *table.renames.borrow_mut() = HashMap::new(); }); - with_resolve_table_mut(|table| *table = HashMap::new()); } /// Reset the tables to their initial state pub fn reset_tables() { with_sctable(|table| { *table.table.borrow_mut() = vec!(EmptyCtxt, IllegalCtxt); - *table.mark_memo.borrow_mut() = HashMap::new(); - *table.rename_memo.borrow_mut() = HashMap::new(); + *table.marks.borrow_mut() = HashMap::new(); + *table.renames.borrow_mut() = HashMap::new(); }); - with_resolve_table_mut(|table| *table = HashMap::new()); } /// Add a value to the end of a vec, return its index @@ -156,103 +144,19 @@ fn idx_push(vec: &mut Vec, val: T) -> u32 { /// Resolve a syntax object to a name, per MTWT. pub fn resolve(id: Ident) -> Name { with_sctable(|sctable| { - with_resolve_table_mut(|resolve_table| { - resolve_internal(id, sctable, resolve_table) - }) + resolve_internal(id, sctable) }) } -type ResolveTable = HashMap<(Name,SyntaxContext),Name>; - -// okay, I admit, putting this in TLS is not so nice: -// fetch the SCTable from TLS, create one if it doesn't yet exist. -fn with_resolve_table_mut(op: F) -> T where - F: FnOnce(&mut ResolveTable) -> T, -{ - thread_local!(static RESOLVE_TABLE_KEY: RefCell = { - RefCell::new(HashMap::new()) - }); - - RESOLVE_TABLE_KEY.with(move |slot| op(&mut *slot.borrow_mut())) -} - /// Resolve a syntax object to a name, per MTWT. /// adding memoization to resolve 500+ seconds in resolve for librustc (!) -fn resolve_internal(id: Ident, - table: &SCTable, - resolve_table: &mut ResolveTable) -> Name { - let key = (id.name, id.ctxt); - - match resolve_table.get(&key) { - Some(&name) => return name, - None => {} - } - - let resolved = { - let result = (*table.table.borrow())[id.ctxt.0 as usize]; - match result { - EmptyCtxt => id.name, - // ignore marks here: - Mark(_,subctxt) => - resolve_internal(Ident::new(id.name, subctxt), - table, resolve_table), - // do the rename if necessary: - Rename(Ident{name, ctxt}, toname, subctxt) => { - let resolvedfrom = - resolve_internal(Ident::new(name, ctxt), - table, resolve_table); - let resolvedthis = - resolve_internal(Ident::new(id.name, subctxt), - table, resolve_table); - if (resolvedthis == resolvedfrom) - && (marksof_internal(ctxt, resolvedthis, table) - == marksof_internal(subctxt, resolvedthis, table)) { - toname - } else { - resolvedthis - } - } - IllegalCtxt => panic!("expected resolvable context, got IllegalCtxt") - } - }; - resolve_table.insert(key, resolved); - resolved -} - -/// Compute the marks associated with a syntax context. -pub fn marksof(ctxt: SyntaxContext, stopname: Name) -> Vec { - with_sctable(|table| marksof_internal(ctxt, stopname, table)) -} - -// the internal function for computing marks -// it's not clear to me whether it's better to use a [] mutable -// vector or a cons-list for this. -fn marksof_internal(ctxt: SyntaxContext, - stopname: Name, - table: &SCTable) -> Vec { - let mut result = Vec::new(); - let mut loopvar = ctxt; - loop { - let table_entry = (*table.table.borrow())[loopvar.0 as usize]; - match table_entry { - EmptyCtxt => { - return result; - }, - Mark(mark, tl) => { - xor_push(&mut result, mark); - loopvar = tl; - }, - Rename(_,name,tl) => { - // see MTWT for details on the purpose of the stopname. - // short version: it prevents duplication of effort. - if name == stopname { - return result; - } else { - loopvar = tl; - } - } - IllegalCtxt => panic!("expected resolvable context, got IllegalCtxt") - } +fn resolve_internal(id: Ident, table: &SCTable) -> Name { + match table.table.borrow()[id.ctxt.0 as usize] { + EmptyCtxt => id.name, + // ignore marks here: + Mark(_, subctxt) => resolve_internal(Ident::new(id.name, subctxt), table), + Rename(name) => name, + IllegalCtxt => panic!("expected resolvable context, got IllegalCtxt") } } @@ -267,103 +171,16 @@ pub fn outer_mark(ctxt: SyntaxContext) -> Mrk { }) } -/// Push a name... unless it matches the one on top, in which -/// case pop and discard (so two of the same marks cancel) -fn xor_push(marks: &mut Vec, mark: Mrk) { - if (!marks.is_empty()) && (*marks.last().unwrap() == mark) { - marks.pop().unwrap(); - } else { - marks.push(mark); - } -} - #[cfg(test)] mod tests { - use self::TestSC::*; use ast::{EMPTY_CTXT, Ident, Mrk, Name, SyntaxContext}; - use super::{resolve, xor_push, apply_mark_internal, new_sctable_internal}; - use super::{apply_rename_internal, apply_renames, marksof_internal, resolve_internal}; - use super::{SCTable, EmptyCtxt, Mark, Rename, IllegalCtxt}; - use std::collections::HashMap; - - #[test] - fn xorpush_test () { - let mut s = Vec::new(); - xor_push(&mut s, 14); - assert_eq!(s.clone(), [14]); - xor_push(&mut s, 14); - assert_eq!(s.clone(), []); - xor_push(&mut s, 14); - assert_eq!(s.clone(), [14]); - xor_push(&mut s, 15); - assert_eq!(s.clone(), [14, 15]); - xor_push(&mut s, 16); - assert_eq!(s.clone(), [14, 15, 16]); - xor_push(&mut s, 16); - assert_eq!(s.clone(), [14, 15]); - xor_push(&mut s, 15); - assert_eq!(s.clone(), [14]); - } + use super::{resolve, apply_mark_internal, new_sctable_internal}; + use super::{SCTable, Mark}; fn id(n: u32, s: SyntaxContext) -> Ident { Ident::new(Name(n), s) } - // because of the SCTable, I now need a tidy way of - // creating syntax objects. Sigh. - #[derive(Clone, PartialEq, Debug)] - enum TestSC { - M(Mrk), - R(Ident,Name) - } - - // unfold a vector of TestSC values into a SCTable, - // returning the resulting index - fn unfold_test_sc(tscs : Vec , tail: SyntaxContext, table: &SCTable) - -> SyntaxContext { - tscs.iter().rev().fold(tail, |tail : SyntaxContext, tsc : &TestSC| - {match *tsc { - M(mrk) => apply_mark_internal(mrk,tail,table), - R(ident,name) => apply_rename_internal(ident,name,tail,table)}}) - } - - // gather a SyntaxContext back into a vector of TestSCs - fn refold_test_sc(mut sc: SyntaxContext, table : &SCTable) -> Vec { - let mut result = Vec::new(); - loop { - let table = table.table.borrow(); - match (*table)[sc.0 as usize] { - EmptyCtxt => {return result;}, - Mark(mrk,tail) => { - result.push(M(mrk)); - sc = tail; - continue; - }, - Rename(id,name,tail) => { - result.push(R(id,name)); - sc = tail; - continue; - } - IllegalCtxt => panic!("expected resolvable context, got IllegalCtxt") - } - } - } - - #[test] - fn test_unfold_refold(){ - let mut t = new_sctable_internal(); - - let test_sc = vec!(M(3),R(id(101,EMPTY_CTXT),Name(14)),M(9)); - assert_eq!(unfold_test_sc(test_sc.clone(),EMPTY_CTXT,&mut t),SyntaxContext(4)); - { - let table = t.table.borrow(); - assert!((*table)[2] == Mark(9,EMPTY_CTXT)); - assert!((*table)[3] == Rename(id(101,EMPTY_CTXT),Name(14),SyntaxContext(2))); - assert!((*table)[4] == Mark(3,SyntaxContext(3))); - } - assert_eq!(refold_test_sc(SyntaxContext(4),&t),test_sc); - } - // extend a syntax context with a sequence of marks given // in a vector. v[0] will be the outermost mark. fn unfold_marks(mrks: Vec , tail: SyntaxContext, table: &SCTable) @@ -383,98 +200,12 @@ mod tests { } } - #[test] - fn test_marksof () { - let stopname = Name(242); - let name1 = Name(243); - let mut t = new_sctable_internal(); - assert_eq!(marksof_internal (EMPTY_CTXT,stopname,&t),Vec::new()); - // FIXME #5074: ANF'd to dodge nested calls - { let ans = unfold_marks(vec!(4,98),EMPTY_CTXT,&mut t); - assert_eq! (marksof_internal (ans,stopname,&t), [4, 98]);} - // does xoring work? - { let ans = unfold_marks(vec!(5,5,16),EMPTY_CTXT,&mut t); - assert_eq! (marksof_internal (ans,stopname,&t), [16]);} - // does nested xoring work? - { let ans = unfold_marks(vec!(5,10,10,5,16),EMPTY_CTXT,&mut t); - assert_eq! (marksof_internal (ans, stopname,&t), [16]);} - // rename where stop doesn't match: - { let chain = vec!(M(9), - R(id(name1.0, - apply_mark_internal (4, EMPTY_CTXT,&mut t)), - Name(100101102)), - M(14)); - let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t); - assert_eq! (marksof_internal (ans, stopname, &t), [9, 14]);} - // rename where stop does match - { let name1sc = apply_mark_internal(4, EMPTY_CTXT, &mut t); - let chain = vec!(M(9), - R(id(name1.0, name1sc), - stopname), - M(14)); - let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t); - assert_eq! (marksof_internal (ans, stopname, &t), [9]); } - } - - - #[test] - fn resolve_tests () { - let a = 40; - let mut t = new_sctable_internal(); - let mut rt = HashMap::new(); - // - ctxt is MT - assert_eq!(resolve_internal(id(a,EMPTY_CTXT),&mut t, &mut rt),Name(a)); - // - simple ignored marks - { let sc = unfold_marks(vec!(1,2,3),EMPTY_CTXT,&mut t); - assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),Name(a));} - // - orthogonal rename where names don't match - { let sc = unfold_test_sc(vec!(R(id(50,EMPTY_CTXT),Name(51)),M(12)),EMPTY_CTXT,&mut t); - assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),Name(a));} - // - rename where names do match, but marks don't - { let sc1 = apply_mark_internal(1,EMPTY_CTXT,&mut t); - let sc = unfold_test_sc(vec!(R(id(a,sc1),Name(50)), - M(1), - M(2)), - EMPTY_CTXT,&mut t); - assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), Name(a));} - // - rename where names and marks match - { let sc1 = unfold_test_sc(vec!(M(1),M(2)),EMPTY_CTXT,&mut t); - let sc = unfold_test_sc(vec!(R(id(a,sc1),Name(50)),M(1),M(2)),EMPTY_CTXT,&mut t); - assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), Name(50)); } - // - rename where names and marks match by literal sharing - { let sc1 = unfold_test_sc(vec!(M(1),M(2)),EMPTY_CTXT,&mut t); - let sc = unfold_test_sc(vec!(R(id(a,sc1),Name(50))),sc1,&mut t); - assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), Name(50)); } - // - two renames of the same var.. can only happen if you use - // local-expand to prevent the inner binding from being renamed - // during the rename-pass caused by the first: - println!("about to run bad test"); - { let sc = unfold_test_sc(vec!(R(id(a,EMPTY_CTXT),Name(50)), - R(id(a,EMPTY_CTXT),Name(51))), - EMPTY_CTXT,&mut t); - assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), Name(51)); } - // the simplest double-rename: - { let a_to_a50 = apply_rename_internal(id(a,EMPTY_CTXT),Name(50),EMPTY_CTXT,&mut t); - let a50_to_a51 = apply_rename_internal(id(a,a_to_a50),Name(51),a_to_a50,&mut t); - assert_eq!(resolve_internal(id(a,a50_to_a51),&mut t, &mut rt),Name(51)); - // mark on the outside doesn't stop rename: - let sc = apply_mark_internal(9,a50_to_a51,&mut t); - assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),Name(51)); - // but mark on the inside does: - let a50_to_a51_b = unfold_test_sc(vec!(R(id(a,a_to_a50),Name(51)), - M(9)), - a_to_a50, - &mut t); - assert_eq!(resolve_internal(id(a,a50_to_a51_b),&mut t, &mut rt),Name(50));} - } - #[test] fn mtwt_resolve_test(){ let a = 40; assert_eq!(resolve(id(a,EMPTY_CTXT)),Name(a)); } - #[test] fn hashing_tests () { let mut t = new_sctable_internal(); @@ -484,26 +215,4 @@ mod tests { assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(2)); // I'm assuming that the rename table will behave the same.... } - - #[test] - fn resolve_table_hashing_tests() { - let mut t = new_sctable_internal(); - let mut rt = HashMap::new(); - assert_eq!(rt.len(),0); - resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt); - assert_eq!(rt.len(),1); - resolve_internal(id(39,EMPTY_CTXT),&mut t, &mut rt); - assert_eq!(rt.len(),2); - resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt); - assert_eq!(rt.len(),2); - } - - #[test] - fn new_resolves_test() { - let renames = vec!((Ident::with_empty_ctxt(Name(23)),Name(24)), - (Ident::with_empty_ctxt(Name(29)),Name(29))); - let new_ctxt1 = apply_renames(&renames,EMPTY_CTXT); - assert_eq!(resolve(Ident::new(Name(23),new_ctxt1)),Name(24)); - assert_eq!(resolve(Ident::new(Name(29),new_ctxt1)),Name(29)); - } } diff --git a/syntex_syntax/src/ext/quote.rs b/syntex_syntax/src/ext/quote.rs index 871b0d4b..68527b07 100644 --- a/syntex_syntax/src/ext/quote.rs +++ b/syntex_syntax/src/ext/quote.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, TokenTree, Ty}; -use codemap::Span; +use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, Ty}; +use syntax_pos::Span; use ext::base::ExtCtxt; use ext::base; use ext::build::AstBuilder; @@ -17,6 +17,7 @@ use parse::parser::{Parser, PathStyle}; use parse::token::*; use parse::token; use ptr::P; +use tokenstream::{self, TokenTree}; /// Quasiquoting works via token trees. /// @@ -31,12 +32,12 @@ pub mod rt { use ext::base::ExtCtxt; use parse::{self, token, classify}; use ptr::P; - use std::rc::Rc; - use ast::TokenTree; + use tokenstream::{self, TokenTree}; pub use parse::new_parser_from_tts; - pub use codemap::{BytePos, Span, dummy_spanned, DUMMY_SP}; + pub use syntax_pos::{BytePos, Span, DUMMY_SP}; + pub use codemap::{dummy_spanned}; pub trait ToTokens { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec; @@ -214,12 +215,12 @@ pub mod rt { if self.node.style == ast::AttrStyle::Inner { r.push(TokenTree::Token(self.span, token::Not)); } - r.push(TokenTree::Delimited(self.span, Rc::new(ast::Delimited { + r.push(TokenTree::Delimited(self.span, tokenstream::Delimited { delim: token::Bracket, open_span: self.span, tts: self.node.value.to_tokens(cx), close_span: self.span, - }))); + })); r } } @@ -234,12 +235,12 @@ pub mod rt { impl ToTokens for () { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Delimited(DUMMY_SP, Rc::new(ast::Delimited { + vec![TokenTree::Delimited(DUMMY_SP, tokenstream::Delimited { delim: token::Paren, open_span: DUMMY_SP, tts: vec![], close_span: DUMMY_SP, - }))] + })] } } @@ -250,7 +251,7 @@ pub mod rt { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(self.clone())), span: DUMMY_SP, - attrs: None, + attrs: ast::ThinVec::new(), }).to_tokens(cx) } } @@ -281,7 +282,7 @@ pub mod rt { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(dummy_spanned(lit))), span: DUMMY_SP, - attrs: None, + attrs: ast::ThinVec::new(), }); if *self >= 0 { return lit.to_tokens(cx); @@ -290,7 +291,7 @@ pub mod rt { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Unary(ast::UnOp::Neg, lit), span: DUMMY_SP, - attrs: None, + attrs: ast::ThinVec::new(), }).to_tokens(cx) } } @@ -512,10 +513,8 @@ pub fn expand_quote_matcher(cx: &mut ExtCtxt, let (cx_expr, tts) = parse_arguments_to_quote(cx, tts); let mut vector = mk_stmts_let(cx, sp); vector.extend(statements_mk_tts(cx, &tts[..], true)); - let block = cx.expr_block( - cx.block_all(sp, - vector, - Some(cx.expr_ident(sp, id_ext("tt"))))); + vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt")))); + let block = cx.expr_block(cx.block(sp, vector)); let expanded = expand_wrapper(cx, sp, cx_expr, block, &[&["syntax", "ext", "quote", "rt"]]); base::MacEager::expr(expanded) @@ -548,7 +547,7 @@ fn mk_name(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P { } fn mk_tt_path(cx: &ExtCtxt, sp: Span, name: &str) -> P { - let idents = vec!(id_ext("syntax"), id_ext("ast"), id_ext("TokenTree"), id_ext(name)); + let idents = vec!(id_ext("syntax"), id_ext("tokenstream"), id_ext("TokenTree"), id_ext(name)); cx.expr_path(cx.path_global(sp, idents)) } @@ -765,19 +764,20 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec cx.expr_some(sp, expr_mk_token(cx, sp, sep)), None => cx.expr_none(sp), }; let e_op = match seq.op { - ast::KleeneOp::ZeroOrMore => "ZeroOrMore", - ast::KleeneOp::OneOrMore => "OneOrMore", + tokenstream::KleeneOp::ZeroOrMore => "ZeroOrMore", + tokenstream::KleeneOp::OneOrMore => "OneOrMore", }; let e_op_idents = vec![ id_ext("syntax"), - id_ext("ast"), + id_ext("tokenstream"), id_ext("KleeneOp"), id_ext(e_op), ]; @@ -787,16 +787,13 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec>(); + stmts.push(cx.stmt_expr(expr)); - cx.expr_block(cx.block_all(sp, stmts, Some(expr))) + cx.expr_block(cx.block(sp, stmts)) } fn expand_parse_call(cx: &ExtCtxt, diff --git a/syntex_syntax/src/ext/source_util.rs b/syntex_syntax/src/ext/source_util.rs index fd229d77..97cb0999 100644 --- a/syntex_syntax/src/ext/source_util.rs +++ b/syntex_syntax/src/ext/source_util.rs @@ -9,8 +9,7 @@ // except according to those terms. use ast; -use codemap::{Pos, Span}; -use codemap; +use syntax_pos::{self, Pos, Span}; use ext::base::*; use ext::base; use ext::build::AstBuilder; @@ -18,6 +17,7 @@ use parse::token; use parse; use print::pprust; use ptr::P; +use tokenstream; use util::small_vector::SmallVector; use std::fs::File; @@ -30,7 +30,7 @@ use std::rc::Rc; // a given file into the current one. /// line!(): expands to the current line number -pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) +pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { base::check_zero_tts(cx, sp, tts, "line!"); @@ -41,7 +41,7 @@ pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } /* column!(): expands to the current column number */ -pub fn expand_column(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) +pub fn expand_column(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { base::check_zero_tts(cx, sp, tts, "column!"); @@ -54,7 +54,7 @@ pub fn expand_column(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) /// file!(): expands to the current filename */ /// The filemap (`loc.file`) contains a bunch more information we could spit /// out if we wanted. -pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) +pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { base::check_zero_tts(cx, sp, tts, "file!"); @@ -64,14 +64,14 @@ pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) base::MacEager::expr(cx.expr_str(topmost, filename)) } -pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) +pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { let s = pprust::tts_to_string(tts); base::MacEager::expr(cx.expr_str(sp, token::intern_and_get_ident(&s[..]))) } -pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) +pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { base::check_zero_tts(cx, sp, tts, "module_path!"); let string = cx.mod_path() @@ -87,7 +87,7 @@ pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) /// include! : parse the given file as an expr /// This is generally a bad idea because it's going to behave /// unhygienically. -pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) +pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include!") { Some(f) => f, @@ -130,7 +130,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree } // include_str! : read the given file, insert it as a literal string expr -pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) +pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { Some(f) => f, @@ -167,7 +167,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } } -pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) +pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") { Some(f) => f, @@ -194,10 +194,11 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // resolve a file-system path to an absolute file-system path (if it // isn't already) -fn res_rel_file(cx: &mut ExtCtxt, sp: codemap::Span, arg: &Path) -> PathBuf { +fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf { // NB: relative paths are resolved relative to the compilation unit if !arg.is_absolute() { - let mut cu = PathBuf::from(&cx.codemap().span_to_filename(sp)); + let callsite = cx.codemap().source_callsite(sp); + let mut cu = PathBuf::from(&cx.codemap().span_to_filename(callsite)); cu.pop(); cu.push(arg); cu diff --git a/syntex_syntax/src/ext/tt/macro_parser.rs b/syntex_syntax/src/ext/tt/macro_parser.rs index ca5eb8f8..813afb93 100644 --- a/syntex_syntax/src/ext/tt/macro_parser.rs +++ b/syntex_syntax/src/ext/tt/macro_parser.rs @@ -79,9 +79,9 @@ pub use self::ParseResult::*; use self::TokenTreeOrTokenTreeVec::*; use ast; -use ast::{TokenTree, Name, Ident}; -use codemap::{BytePos, mk_sp, Span, Spanned}; -use codemap; +use ast::{Name, Ident}; +use syntax_pos::{self, BytePos, mk_sp, Span}; +use codemap::Spanned; use errors::FatalError; use parse::lexer::*; //resolve bug? use parse::ParseSess; @@ -91,6 +91,7 @@ use parse::token::{Token, Nonterminal}; use parse::token; use print::pprust; use ptr::P; +use tokenstream::{self, TokenTree}; use std::mem; use std::rc::Rc; @@ -102,8 +103,8 @@ use std::collections::hash_map::Entry::{Vacant, Occupied}; #[derive(Clone)] enum TokenTreeOrTokenTreeVec { - Tt(ast::TokenTree), - TtSeq(Rc>), + Tt(tokenstream::TokenTree), + TtSeq(Rc>), } impl TokenTreeOrTokenTreeVec { @@ -196,7 +197,7 @@ pub fn initial_matcher_pos(ms: Rc>, sep: Option, lo: ByteP /// token tree it was derived from. pub enum NamedMatch { - MatchedSeq(Vec>, codemap::Span), + MatchedSeq(Vec>, syntax_pos::Span), MatchedNonterminal(Nonterminal) } @@ -204,7 +205,7 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) -> ParseResult>> { fn n_rec(p_s: &ParseSess, m: &TokenTree, res: &[Rc], ret_val: &mut HashMap>, idx: &mut usize) - -> Result<(), (codemap::Span, String)> { + -> Result<(), (syntax_pos::Span, String)> { match *m { TokenTree::Sequence(_, ref seq) => { for next_m in &seq.tts { @@ -251,9 +252,9 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) pub enum ParseResult { Success(T), /// Arm failed to match - Failure(codemap::Span, String), + Failure(syntax_pos::Span, String), /// Fatal error (malformed macro?). Abort compilation. - Error(codemap::Span, String) + Error(syntax_pos::Span, String) } pub type NamedParseResult = ParseResult>>; @@ -374,7 +375,7 @@ pub fn parse(sess: &ParseSess, match ei.top_elts.get_tt(idx) { /* need to descend into sequence */ TokenTree::Sequence(sp, seq) => { - if seq.op == ast::KleeneOp::ZeroOrMore { + if seq.op == tokenstream::KleeneOp::ZeroOrMore { let mut new_ei = ei.clone(); new_ei.match_cur += seq.num_captures; new_ei.idx += 1; diff --git a/syntex_syntax/src/ext/tt/macro_rules.rs b/syntex_syntax/src/ext/tt/macro_rules.rs index bbe989b0..23f0b1ff 100644 --- a/syntex_syntax/src/ext/tt/macro_rules.rs +++ b/syntex_syntax/src/ext/tt/macro_rules.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{self, TokenTree}; -use codemap::{Span, DUMMY_SP}; +use ast; +use syntax_pos::{Span, DUMMY_SP}; use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; use ext::base::{NormalTT, TTMacroExpander}; use ext::tt::macro_parser::{Success, Error, Failure}; @@ -21,13 +21,13 @@ use parse::token::{self, gensym_ident, NtTT, Token}; use parse::token::Token::*; use print; use ptr::P; +use tokenstream::{self, TokenTree}; use util::small_vector::SmallVector; use std::cell::RefCell; use std::collections::{HashMap}; use std::collections::hash_map::{Entry}; -use std::rc::Rc; struct ParserAnyMacro<'a> { parser: RefCell>, @@ -100,6 +100,21 @@ impl<'a> MacResult for ParserAnyMacro<'a> { Some(ret) } + fn make_trait_items(self: Box>) + -> Option> { + let mut ret = SmallVector::zero(); + loop { + let mut parser = self.parser.borrow_mut(); + match parser.token { + token::Eof => break, + _ => ret.push(panictry!(parser.parse_trait_item())) + } + } + self.ensure_complete_parse(false, "item"); + Some(ret) + } + + fn make_stmts(self: Box>) -> Option> { let mut ret = SmallVector::zero(); @@ -246,27 +261,25 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt, // These spans won't matter, anyways let match_lhs_tok = MatchNt(lhs_nm, token::str_to_ident("tt")); let match_rhs_tok = MatchNt(rhs_nm, token::str_to_ident("tt")); - let argument_gram = vec!( - TokenTree::Sequence(DUMMY_SP, - Rc::new(ast::SequenceRepetition { - tts: vec![ - TokenTree::Token(DUMMY_SP, match_lhs_tok), - TokenTree::Token(DUMMY_SP, token::FatArrow), - TokenTree::Token(DUMMY_SP, match_rhs_tok)], - separator: Some(token::Semi), - op: ast::KleeneOp::OneOrMore, - num_captures: 2 - })), - //to phase into semicolon-termination instead of - //semicolon-separation - TokenTree::Sequence(DUMMY_SP, - Rc::new(ast::SequenceRepetition { - tts: vec![TokenTree::Token(DUMMY_SP, token::Semi)], - separator: None, - op: ast::KleeneOp::ZeroOrMore, - num_captures: 0 - }))); - + let argument_gram = vec![ + TokenTree::Sequence(DUMMY_SP, tokenstream::SequenceRepetition { + tts: vec![ + TokenTree::Token(DUMMY_SP, match_lhs_tok), + TokenTree::Token(DUMMY_SP, token::FatArrow), + TokenTree::Token(DUMMY_SP, match_rhs_tok), + ], + separator: Some(token::Semi), + op: tokenstream::KleeneOp::OneOrMore, + num_captures: 2, + }), + // to phase into semicolon-termination instead of semicolon-separation + TokenTree::Sequence(DUMMY_SP, tokenstream::SequenceRepetition { + tts: vec![TokenTree::Token(DUMMY_SP, token::Semi)], + separator: None, + op: tokenstream::KleeneOp::ZeroOrMore, + num_captures: 0 + }), + ]; // Parse the macro_rules! invocation (`none` is for no interpolations): let arg_reader = new_tt_reader(&cx.parse_sess().span_diagnostic, @@ -427,7 +440,7 @@ impl FirstSets { } // Reverse scan: Sequence comes before `first`. - if subfirst.maybe_empty || seq_rep.op == ast::KleeneOp::ZeroOrMore { + if subfirst.maybe_empty || seq_rep.op == tokenstream::KleeneOp::ZeroOrMore { // If sequence is potentially empty, then // union them (preserving first emptiness). first.add_all(&TokenSet { maybe_empty: true, ..subfirst }); @@ -474,7 +487,8 @@ impl FirstSets { assert!(first.maybe_empty); first.add_all(subfirst); - if subfirst.maybe_empty || seq_rep.op == ast::KleeneOp::ZeroOrMore { + if subfirst.maybe_empty || + seq_rep.op == tokenstream::KleeneOp::ZeroOrMore { // continue scanning for more first // tokens, but also make sure we // restore empty-tracking state diff --git a/syntex_syntax/src/ext/tt/transcribe.rs b/syntex_syntax/src/ext/tt/transcribe.rs index 6b3b5ce9..58328eb4 100644 --- a/syntex_syntax/src/ext/tt/transcribe.rs +++ b/syntex_syntax/src/ext/tt/transcribe.rs @@ -9,15 +9,15 @@ // except according to those terms. use self::LockstepIterSize::*; -use ast; -use ast::{TokenTree, Ident, Name}; -use codemap::{Span, DUMMY_SP}; +use ast::{Ident, Name}; +use syntax_pos::{Span, DUMMY_SP}; use errors::{Handler, DiagnosticBuilder}; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use parse::token::{DocComment, MatchNt, SubstNt}; use parse::token::{Token, NtIdent, SpecialMacroVar}; use parse::token; use parse::lexer::TokenAndSpan; +use tokenstream::{self, TokenTree}; use std::rc::Rc; use std::ops::Add; @@ -59,7 +59,7 @@ pub struct TtReader<'a> { pub fn new_tt_reader(sp_diag: &Handler, interp: Option>>, imported_from: Option, - src: Vec) + src: Vec) -> TtReader { new_tt_reader_with_doc_flag(sp_diag, interp, imported_from, src, false) } @@ -73,17 +73,17 @@ pub fn new_tt_reader(sp_diag: &Handler, pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler, interp: Option>>, imported_from: Option, - src: Vec, + src: Vec, desugar_doc_comments: bool) -> TtReader { let mut r = TtReader { sp_diag: sp_diag, stack: vec!(TtFrame { - forest: TokenTree::Sequence(DUMMY_SP, Rc::new(ast::SequenceRepetition { + forest: TokenTree::Sequence(DUMMY_SP, tokenstream::SequenceRepetition { tts: src, // doesn't matter. This merely holds the root unzipping. - separator: None, op: ast::KleeneOp::ZeroOrMore, num_captures: 0 - })), + separator: None, op: tokenstream::KleeneOp::ZeroOrMore, num_captures: 0 + }), idx: 0, dotdotdoted: false, sep: None, @@ -259,7 +259,7 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { } LisConstraint(len, _) => { if len == 0 { - if seq.op == ast::KleeneOp::OneOrMore { + if seq.op == tokenstream::KleeneOp::OneOrMore { // FIXME #2887 blame invoker panic!(r.sp_diag.span_fatal(sp.clone(), "this must repeat at least once")); diff --git a/syntex_syntax/src/feature_gate.rs b/syntex_syntax/src/feature_gate.rs index 550eb0a5..d6476fdb 100644 --- a/syntex_syntax/src/feature_gate.rs +++ b/syntex_syntax/src/feature_gate.rs @@ -30,10 +30,10 @@ use ast::{NodeId, PatKind}; use ast; use attr; use attr::AttrMetaMethods; -use codemap::{CodeMap, Span}; +use codemap::CodeMap; +use syntax_pos::Span; use errors::Handler; -use visit; -use visit::{FnKind, Visitor}; +use visit::{self, FnKind, Visitor}; use parse::ParseSess; use parse::token::InternedString; @@ -800,7 +800,7 @@ macro_rules! gate_feature_post { }} } -impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { +impl<'a> Visitor for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { if !self.context.cm.span_allows_unstable(attr.span) { self.context.check_attribute(attr, false); @@ -996,9 +996,9 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } fn visit_fn(&mut self, - fn_kind: FnKind<'v>, - fn_decl: &'v ast::FnDecl, - block: &'v ast::Block, + fn_kind: FnKind, + fn_decl: &ast::FnDecl, + block: &ast::Block, span: Span, _node_id: NodeId) { // check for const fn declarations @@ -1037,7 +1037,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { visit::walk_fn(self, fn_kind, fn_decl, block, span); } - fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) { + fn visit_trait_item(&mut self, ti: &ast::TraitItem) { match ti.node { ast::TraitItemKind::Const(..) => { gate_feature_post!(&self, associated_consts, @@ -1058,7 +1058,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { visit::walk_trait_item(self, ti); } - fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) { + fn visit_impl_item(&mut self, ii: &ast::ImplItem) { if ii.defaultness == ast::Defaultness::Default { gate_feature_post!(&self, specialization, ii.span, @@ -1081,7 +1081,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { visit::walk_impl_item(self, ii); } - fn visit_vis(&mut self, vis: &'v ast::Visibility) { + fn visit_vis(&mut self, vis: &ast::Visibility) { let span = match *vis { ast::Visibility::Crate(span) => span, ast::Visibility::Restricted { ref path, .. } => path.span, diff --git a/syntex_syntax/src/fold.rs b/syntex_syntax/src/fold.rs index edf418e3..ed6f09ee 100644 --- a/syntex_syntax/src/fold.rs +++ b/syntex_syntax/src/fold.rs @@ -20,15 +20,14 @@ use ast::*; use ast; -use attr::{ThinAttributes, ThinAttributesExt}; -use codemap::{respan, Span, Spanned}; +use syntax_pos::Span; +use codemap::{Spanned, respan}; use parse::token::{self, keywords}; use ptr::P; +use tokenstream::*; use util::small_vector::SmallVector; use util::move_map::MoveMap; -use std::rc::Rc; - pub trait Folder : Sized { // Any additions to this trait should happen in form // of a call to a public `noop_*` function that only calls @@ -102,10 +101,6 @@ pub trait Folder : Sized { noop_fold_pat(p, self) } - fn fold_decl(&mut self, d: P) -> SmallVector> { - noop_fold_decl(d, self) - } - fn fold_expr(&mut self, e: P) -> P { e.map(|e| noop_fold_expr(e, self)) } @@ -227,11 +222,11 @@ pub trait Folder : Sized { noop_fold_ty_params(tps, self) } - fn fold_tt(&mut self, tt: &TokenTree) -> TokenTree { + fn fold_tt(&mut self, tt: TokenTree) -> TokenTree { noop_fold_tt(tt, self) } - fn fold_tts(&mut self, tts: &[TokenTree]) -> Vec { + fn fold_tts(&mut self, tts: Vec) -> Vec { noop_fold_tts(tts, self) } @@ -336,8 +331,8 @@ pub fn fold_attrs(attrs: Vec, fld: &mut T) -> Vec(attrs: ThinAttributes, fld: &mut T) -> ThinAttributes { - attrs.map_thin_attrs(|v| fold_attrs(v, fld)) +pub fn fold_thin_attrs(attrs: ThinVec, fld: &mut T) -> ThinVec { + fold_attrs(attrs.into(), fld).into() } pub fn noop_fold_arm(Arm {attrs, pats, guard, body}: Arm, fld: &mut T) -> Arm { @@ -349,19 +344,6 @@ pub fn noop_fold_arm(Arm {attrs, pats, guard, body}: Arm, fld: &mut T } } -pub fn noop_fold_decl(d: P, fld: &mut T) -> SmallVector> { - d.and_then(|Spanned {node, span}| match node { - DeclKind::Local(l) => SmallVector::one(P(Spanned { - node: DeclKind::Local(fld.fold_local(l)), - span: fld.new_span(span) - })), - DeclKind::Item(it) => fld.fold_item(it).into_iter().map(|i| P(Spanned { - node: DeclKind::Item(i), - span: fld.new_span(span) - })).collect() - }) -} - pub fn noop_fold_ty_binding(b: TypeBinding, fld: &mut T) -> TypeBinding { TypeBinding { id: fld.new_id(b.id), @@ -498,7 +480,7 @@ pub fn noop_fold_local(l: P, fld: &mut T) -> P { pat: fld.fold_pat(pat), init: init.map(|e| fld.fold_expr(e)), span: fld.new_span(span), - attrs: attrs.map_thin_attrs(|v| fold_attrs(v, fld)), + attrs: fold_attrs(attrs.into(), fld).into(), }) } @@ -519,8 +501,7 @@ pub fn noop_fold_mac(Spanned {node, span}: Mac, fld: &mut T) -> Mac { Spanned { node: Mac_ { path: fld.fold_path(node.path), - tts: fld.fold_tts(&node.tts), - ctxt: node.ctxt, + tts: fld.fold_tts(node.tts), }, span: fld.new_span(span) } @@ -547,34 +528,26 @@ pub fn noop_fold_arg(Arg {id, pat, ty}: Arg, fld: &mut T) -> Arg { } } -pub fn noop_fold_tt(tt: &TokenTree, fld: &mut T) -> TokenTree { - match *tt { +pub fn noop_fold_tt(tt: TokenTree, fld: &mut T) -> TokenTree { + match tt { TokenTree::Token(span, ref tok) => TokenTree::Token(span, fld.fold_token(tok.clone())), - TokenTree::Delimited(span, ref delimed) => { - TokenTree::Delimited(span, Rc::new( - Delimited { - delim: delimed.delim, - open_span: delimed.open_span, - tts: fld.fold_tts(&delimed.tts), - close_span: delimed.close_span, - } - )) - }, - TokenTree::Sequence(span, ref seq) => - TokenTree::Sequence(span, - Rc::new(SequenceRepetition { - tts: fld.fold_tts(&seq.tts), - separator: seq.separator.clone().map(|tok| fld.fold_token(tok)), - ..**seq - })), + TokenTree::Delimited(span, delimed) => TokenTree::Delimited(span, Delimited { + delim: delimed.delim, + open_span: delimed.open_span, + tts: fld.fold_tts(delimed.tts), + close_span: delimed.close_span, + }), + TokenTree::Sequence(span, seq) => TokenTree::Sequence(span, SequenceRepetition { + tts: fld.fold_tts(seq.tts), + separator: seq.separator.clone().map(|tok| fld.fold_token(tok)), + ..seq + }), } } -pub fn noop_fold_tts(tts: &[TokenTree], fld: &mut T) -> Vec { - // FIXME: Does this have to take a tts slice? - // Could use move_map otherwise... - tts.iter().map(|tt| fld.fold_tt(tt)).collect() +pub fn noop_fold_tts(tts: Vec, fld: &mut T) -> Vec { + tts.move_map(|tt| fld.fold_tt(tt)) } // apply ident folder if it's an ident, apply other folds to interpolated nodes @@ -632,7 +605,7 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtIdent(Box::new(Spanned::{node: fld.fold_ident(id.node), ..*id})), token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)), token::NtPath(path) => token::NtPath(Box::new(fld.fold_path(*path))), - token::NtTT(tt) => token::NtTT(P(fld.fold_tt(&tt))), + token::NtTT(tt) => token::NtTT(tt.map(|tt| fld.fold_tt(tt))), token::NtArm(arm) => token::NtArm(fld.fold_arm(arm)), token::NtImplItem(arm) => token::NtImplItem(arm.map(|arm| fld.fold_impl_item(arm) @@ -845,10 +818,9 @@ fn noop_fold_bounds(bounds: TyParamBounds, folder: &mut T) } pub fn noop_fold_block(b: P, folder: &mut T) -> P { - b.map(|Block {id, stmts, expr, rules, span}| Block { + b.map(|Block {id, stmts, rules, span}| Block { id: folder.new_id(id), stmts: stmts.move_flat_map(|s| folder.fold_stmt(s).into_iter()), - expr: expr.and_then(|x| folder.fold_opt_expr(x)), rules: rules, span: folder.new_span(span), }) @@ -945,6 +917,9 @@ pub fn noop_fold_trait_item(i: TraitItem, folder: &mut T) TraitItemKind::Type(folder.fold_bounds(bounds), default.map(|x| folder.fold_ty(x))) } + ast::TraitItemKind::Macro(mac) => { + TraitItemKind::Macro(folder.fold_mac(mac)) + } }, span: folder.new_span(i.span) }) @@ -1088,12 +1063,11 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { PatKind::TupleStruct(folder.fold_path(pth), pats.move_map(|x| folder.fold_pat(x)), ddpos) } - PatKind::Path(pth) => { - PatKind::Path(folder.fold_path(pth)) - } - PatKind::QPath(qself, pth) => { - let qself = QSelf {ty: folder.fold_ty(qself.ty), .. qself}; - PatKind::QPath(qself, folder.fold_path(pth)) + PatKind::Path(opt_qself, pth) => { + let opt_qself = opt_qself.map(|qself| { + QSelf { ty: folder.fold_ty(qself.ty), position: qself.position } + }); + PatKind::Path(opt_qself, folder.fold_path(pth)) } PatKind::Struct(pth, fields, etc) => { let pth = folder.fold_path(pth); @@ -1128,7 +1102,6 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mut T) -> Expr { Expr { - id: folder.new_id(id), node: match node { ExprKind::Box(e) => { ExprKind::Box(folder.fold_expr(e)) @@ -1255,7 +1228,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu respan(folder.new_span(label.span), folder.fold_ident(label.node))) ), - ExprKind::Again(opt_ident) => ExprKind::Again(opt_ident.map(|label| + ExprKind::Continue(opt_ident) => ExprKind::Continue(opt_ident.map(|label| respan(folder.new_span(label.span), folder.fold_ident(label.node))) ), @@ -1296,11 +1269,21 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu fields.move_map(|x| folder.fold_field(x)), maybe_expr.map(|x| folder.fold_expr(x))) }, - ExprKind::Paren(ex) => ExprKind::Paren(folder.fold_expr(ex)), + ExprKind::Paren(ex) => { + let sub_expr = folder.fold_expr(ex); + return Expr { + // Nodes that are equal modulo `Paren` sugar no-ops should have the same ids. + id: sub_expr.id, + node: ExprKind::Paren(sub_expr), + span: folder.new_span(span), + attrs: fold_attrs(attrs.into(), folder).into(), + }; + } ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)), }, + id: folder.new_id(id), span: folder.new_span(span), - attrs: attrs.map_thin_attrs(|v| fold_attrs(v, folder)), + attrs: fold_attrs(attrs.into(), folder).into(), } } @@ -1312,44 +1295,50 @@ pub fn noop_fold_exprs(es: Vec>, folder: &mut T) -> Vec(Spanned {node, span}: Stmt, folder: &mut T) +pub fn noop_fold_stmt(Stmt {node, span, id}: Stmt, folder: &mut T) -> SmallVector { + let id = folder.new_id(id); let span = folder.new_span(span); + match node { - StmtKind::Decl(d, id) => { - let id = folder.new_id(id); - folder.fold_decl(d).into_iter().map(|d| Spanned { - node: StmtKind::Decl(d, id), - span: span - }).collect() - } - StmtKind::Expr(e, id) => { - let id = folder.new_id(id); - if let Some(e) = folder.fold_opt_expr(e) { - SmallVector::one(Spanned { - node: StmtKind::Expr(e, id), - span: span + StmtKind::Local(local) => SmallVector::one(Stmt { + id: id, + node: StmtKind::Local(folder.fold_local(local)), + span: span, + }), + StmtKind::Item(item) => folder.fold_item(item).into_iter().map(|item| Stmt { + id: id, + node: StmtKind::Item(item), + span: span, + }).collect(), + StmtKind::Expr(expr) => { + if let Some(expr) = folder.fold_opt_expr(expr) { + SmallVector::one(Stmt { + id: id, + node: StmtKind::Expr(expr), + span: span, }) } else { SmallVector::zero() } } - StmtKind::Semi(e, id) => { - let id = folder.new_id(id); - if let Some(e) = folder.fold_opt_expr(e) { - SmallVector::one(Spanned { - node: StmtKind::Semi(e, id), - span: span + StmtKind::Semi(expr) => { + if let Some(expr) = folder.fold_opt_expr(expr) { + SmallVector::one(Stmt { + id: id, + node: StmtKind::Semi(expr), + span: span, }) } else { SmallVector::zero() } } - StmtKind::Mac(mac, semi, attrs) => SmallVector::one(Spanned { - node: StmtKind::Mac(mac.map(|m| folder.fold_mac(m)), - semi, - attrs.map_thin_attrs(|v| fold_attrs(v, folder))), - span: span + StmtKind::Mac(mac) => SmallVector::one(Stmt { + id: id, + node: StmtKind::Mac(mac.map(|(mac, semi, attrs)| { + (folder.fold_mac(mac), semi, fold_attrs(attrs.into(), folder).into()) + })), + span: span, }) } } diff --git a/syntex_syntax/src/errors/json.rs b/syntex_syntax/src/json.rs similarity index 97% rename from syntex_syntax/src/errors/json.rs rename to syntex_syntax/src/json.rs index 93c6268c..dc9a5ee4 100644 --- a/syntex_syntax/src/errors/json.rs +++ b/syntex_syntax/src/json.rs @@ -19,10 +19,10 @@ // FIXME spec the JSON output properly. - -use codemap::{self, MacroBacktrace, Span, SpanLabel, MultiSpan, CodeMap}; -use diagnostics::registry::Registry; -use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion}; +use codemap::CodeMap; +use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan}; +use errors::registry::Registry; +use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper}; use errors::emitter::Emitter; use std::rc::Rc; @@ -34,7 +34,7 @@ use rustc_serialize::json::as_json; pub struct JsonEmitter { dst: Box, registry: Option, - cm: Rc, + cm: Rc, } impl JsonEmitter { @@ -303,7 +303,7 @@ impl DiagnosticSpan { } impl DiagnosticSpanLine { - fn line_from_filemap(fm: &codemap::FileMap, + fn line_from_filemap(fm: &syntax_pos::FileMap, index: usize, h_start: usize, h_end: usize) @@ -354,12 +354,14 @@ impl DiagnosticCode { impl JsonEmitter { fn render(&self, render_span: &RenderSpan) -> Option { + use std::borrow::Borrow; + match *render_span { RenderSpan::FullSpan(_) => { None } RenderSpan::Suggestion(ref suggestion) => { - Some(suggestion.splice_lines(&self.cm)) + Some(suggestion.splice_lines(self.cm.borrow())) } } } diff --git a/syntex_syntax/src/lib.rs b/syntex_syntax/src/lib.rs index 420a41e0..652cf68d 100644 --- a/syntex_syntax/src/lib.rs +++ b/syntex_syntax/src/lib.rs @@ -33,7 +33,6 @@ #![feature(str_escape)] #![feature(unicode)] #![feature(question_mark)] -#![feature(range_contains)] extern crate serialize; extern crate term; @@ -41,9 +40,12 @@ extern crate libc; #[macro_use] extern crate log; #[macro_use] #[no_link] extern crate rustc_bitflags; extern crate rustc_unicode; +pub extern crate rustc_errors as errors; +extern crate syntax_pos; extern crate serialize as rustc_serialize; // used by deriving + // A variant of 'try!' that panics on an Err. This is used as a crutch on the // way towards a non-panic!-prone parser. It should be used for fatal parsing // errors; eventually we plan to convert all code using panictry to just use @@ -53,7 +55,7 @@ extern crate serialize as rustc_serialize; // used by deriving macro_rules! panictry { ($e:expr) => ({ use std::result::Result::{Ok, Err}; - use $crate::errors::FatalError; + use errors::FatalError; match $e { Ok(e) => e, Err(mut e) => { @@ -73,16 +75,18 @@ pub mod util { pub mod parser_testing; pub mod small_vector; pub mod move_map; + + mod thin_vec; + pub use self::thin_vec::ThinVec; } pub mod diagnostics { pub mod macros; pub mod plugin; - pub mod registry; pub mod metadata; } -pub mod errors; +pub mod json; pub mod syntax { pub use ext; @@ -104,6 +108,7 @@ pub mod show_span; pub mod std_inject; pub mod str; pub mod test; +pub mod tokenstream; pub mod visit; pub mod print { diff --git a/syntex_syntax/src/parse/attr.rs b/syntex_syntax/src/parse/attr.rs index db643eb0..f6e94b7c 100644 --- a/syntex_syntax/src/parse/attr.rs +++ b/syntex_syntax/src/parse/attr.rs @@ -10,7 +10,8 @@ use attr; use ast; -use codemap::{spanned, Spanned, mk_sp, Span}; +use syntax_pos::{mk_sp, Span}; +use codemap::{spanned, Spanned}; use parse::common::SeqSep; use parse::PResult; use parse::token; diff --git a/syntex_syntax/src/parse/classify.rs b/syntex_syntax/src/parse/classify.rs index 89110f31..4fe4ec7e 100644 --- a/syntex_syntax/src/parse/classify.rs +++ b/syntex_syntax/src/parse/classify.rs @@ -47,13 +47,9 @@ pub fn expr_is_simple_block(e: &ast::Expr) -> bool { /// seen the semicolon, and thus don't need another. pub fn stmt_ends_with_semi(stmt: &ast::StmtKind) -> bool { match *stmt { - ast::StmtKind::Decl(ref d, _) => { - match d.node { - ast::DeclKind::Local(_) => true, - ast::DeclKind::Item(_) => false, - } - } - ast::StmtKind::Expr(ref e, _) => expr_requires_semi_to_be_stmt(e), + ast::StmtKind::Local(_) => true, + ast::StmtKind::Item(_) => false, + ast::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(e), ast::StmtKind::Semi(..) => false, ast::StmtKind::Mac(..) => false, } diff --git a/syntex_syntax/src/parse/lexer/comments.rs b/syntex_syntax/src/parse/lexer/comments.rs index 06d255d5..5eb5605e 100644 --- a/syntex_syntax/src/parse/lexer/comments.rs +++ b/syntex_syntax/src/parse/lexer/comments.rs @@ -11,7 +11,8 @@ pub use self::CommentStyle::*; use ast; -use codemap::{BytePos, CharPos, CodeMap, Pos}; +use codemap::CodeMap; +use syntax_pos::{BytePos, CharPos, Pos}; use errors; use parse::lexer::is_block_doc_comment; use parse::lexer::{StringReader, TokenAndSpan}; diff --git a/syntex_syntax/src/parse/lexer/mod.rs b/syntex_syntax/src/parse/lexer/mod.rs index d78a81de..809f4daa 100644 --- a/syntex_syntax/src/parse/lexer/mod.rs +++ b/syntex_syntax/src/parse/lexer/mod.rs @@ -9,8 +9,8 @@ // except according to those terms. use ast; -use codemap::{BytePos, CharPos, CodeMap, Pos, Span}; -use codemap; +use syntax_pos::{self, BytePos, CharPos, Pos, Span}; +use codemap::CodeMap; use errors::{FatalError, Handler, DiagnosticBuilder}; use ext::tt::transcribe::tt_next_token; use parse::token::{self, keywords, str_to_ident}; @@ -84,7 +84,7 @@ pub struct StringReader<'a> { pub col: CharPos, /// The last character to be read pub curr: Option, - pub filemap: Rc, + pub filemap: Rc, // cached: pub peek_tok: token::Token, pub peek_span: Span, @@ -162,7 +162,7 @@ impl<'a> Reader for TtReader<'a> { impl<'a> StringReader<'a> { /// For comments.rs, which hackily pokes into pos and curr pub fn new_raw<'b>(span_diagnostic: &'b Handler, - filemap: Rc) + filemap: Rc) -> StringReader<'b> { if filemap.src.is_none() { span_diagnostic.bug(&format!("Cannot lex filemap \ @@ -181,7 +181,7 @@ impl<'a> StringReader<'a> { filemap: filemap, // dummy values; not read peek_tok: token::Eof, - peek_span: codemap::DUMMY_SP, + peek_span: syntax_pos::DUMMY_SP, source_text: source_text, fatal_errs: Vec::new(), }; @@ -190,7 +190,7 @@ impl<'a> StringReader<'a> { } pub fn new<'b>(span_diagnostic: &'b Handler, - filemap: Rc) + filemap: Rc) -> StringReader<'b> { let mut sr = StringReader::new_raw(span_diagnostic, filemap); if let Err(_) = sr.advance_token() { @@ -217,12 +217,12 @@ impl<'a> StringReader<'a> { /// Report a fatal error spanning [`from_pos`, `to_pos`). fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError { - self.fatal_span(codemap::mk_sp(from_pos, to_pos), m) + self.fatal_span(syntax_pos::mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`). fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) { - self.err_span(codemap::mk_sp(from_pos, to_pos), m) + self.err_span(syntax_pos::mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an @@ -246,7 +246,7 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } - self.span_diagnostic.struct_span_fatal(codemap::mk_sp(from_pos, to_pos), &m[..]) + self.span_diagnostic.struct_span_fatal(syntax_pos::mk_sp(from_pos, to_pos), &m[..]) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an @@ -270,7 +270,7 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } - self.span_diagnostic.struct_span_err(codemap::mk_sp(from_pos, to_pos), &m[..]) + self.span_diagnostic.struct_span_err(syntax_pos::mk_sp(from_pos, to_pos), &m[..]) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the @@ -294,11 +294,11 @@ impl<'a> StringReader<'a> { None => { if self.is_eof() { self.peek_tok = token::Eof; - self.peek_span = codemap::mk_sp(self.filemap.end_pos, self.filemap.end_pos); + self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos); } else { let start_bytepos = self.last_pos; self.peek_tok = self.next_token_inner()?; - self.peek_span = codemap::mk_sp(start_bytepos, self.last_pos); + self.peek_span = syntax_pos::mk_sp(start_bytepos, self.last_pos); }; } } @@ -473,7 +473,7 @@ impl<'a> StringReader<'a> { match self.curr { Some(c) => { if c.is_whitespace() { - self.span_diagnostic.span_err(codemap::mk_sp(self.last_pos, self.last_pos), + self.span_diagnostic.span_err(syntax_pos::mk_sp(self.last_pos, self.last_pos), "called consume_any_line_comment, but there \ was whitespace"); } @@ -524,13 +524,13 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: codemap::mk_sp(start_bpos, self.last_pos), + sp: syntax_pos::mk_sp(start_bpos, self.last_pos), }) }) } else { Some(TokenAndSpan { tok: token::Comment, - sp: codemap::mk_sp(start_bpos, self.last_pos), + sp: syntax_pos::mk_sp(start_bpos, self.last_pos), }) }; } @@ -563,7 +563,7 @@ impl<'a> StringReader<'a> { } return Some(TokenAndSpan { tok: token::Shebang(self.name_from(start)), - sp: codemap::mk_sp(start, self.last_pos), + sp: syntax_pos::mk_sp(start, self.last_pos), }); } } @@ -591,7 +591,7 @@ impl<'a> StringReader<'a> { } let c = Some(TokenAndSpan { tok: token::Whitespace, - sp: codemap::mk_sp(start_bpos, self.last_pos), + sp: syntax_pos::mk_sp(start_bpos, self.last_pos), }); debug!("scanning whitespace: {:?}", c); c @@ -653,7 +653,7 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: codemap::mk_sp(start_bpos, self.last_pos), + sp: syntax_pos::mk_sp(start_bpos, self.last_pos), }) }) } @@ -850,7 +850,7 @@ impl<'a> StringReader<'a> { let valid = if self.curr_is('{') { self.scan_unicode_escape(delim) && !ascii_only } else { - let span = codemap::mk_sp(start, self.last_pos); + let span = syntax_pos::mk_sp(start, self.last_pos); self.span_diagnostic .struct_span_err(span, "incorrect unicode escape sequence") .span_help(span, @@ -888,13 +888,13 @@ impl<'a> StringReader<'a> { }, c); if e == '\r' { - err.span_help(codemap::mk_sp(escaped_pos, last_pos), + err.span_help(syntax_pos::mk_sp(escaped_pos, last_pos), "this is an isolated carriage return; consider \ checking your editor and version control \ settings"); } if (e == '{' || e == '}') && !ascii_only { - err.span_help(codemap::mk_sp(escaped_pos, last_pos), + err.span_help(syntax_pos::mk_sp(escaped_pos, last_pos), "if used in a formatting string, curly braces \ are escaped with `{{` and `}}`"); } @@ -1677,7 +1677,8 @@ fn ident_continue(c: Option) -> bool { mod tests { use super::*; - use codemap::{BytePos, CodeMap, Span, NO_EXPANSION}; + use syntax_pos::{BytePos, Span, NO_EXPANSION}; + use codemap::CodeMap; use errors; use parse::token; use parse::token::str_to_ident; @@ -1686,7 +1687,10 @@ mod tests { fn mk_sh(cm: Rc) -> errors::Handler { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), None, cm); + let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), + None, + cm, + errors::snippet::FormatMode::EnvironmentSelected); errors::Handler::with_emitter(true, false, Box::new(emitter)) } @@ -1889,7 +1893,7 @@ mod tests { let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string()); let comment = lexer.next_token(); assert_eq!(comment.tok, token::Comment); - assert_eq!(comment.sp, ::codemap::mk_sp(BytePos(0), BytePos(7))); + assert_eq!(comment.sp, ::syntax_pos::mk_sp(BytePos(0), BytePos(7))); assert_eq!(lexer.next_token().tok, token::Whitespace); assert_eq!(lexer.next_token().tok, token::DocComment(token::intern("/// test"))); diff --git a/syntex_syntax/src/parse/lexer/unicode_chars.rs b/syntex_syntax/src/parse/lexer/unicode_chars.rs index d337c78b..dab97d1d 100644 --- a/syntex_syntax/src/parse/lexer/unicode_chars.rs +++ b/syntex_syntax/src/parse/lexer/unicode_chars.rs @@ -11,7 +11,7 @@ // Characters and their corresponding confusables were collected from // http://www.unicode.org/Public/security/revision-06/confusables.txt -use codemap::mk_sp as make_span; +use syntax_pos::mk_sp as make_span; use errors::DiagnosticBuilder; use super::StringReader; diff --git a/syntex_syntax/src/parse/mod.rs b/syntex_syntax/src/parse/mod.rs index 2e4d46bc..bbcc044d 100644 --- a/syntex_syntax/src/parse/mod.rs +++ b/syntex_syntax/src/parse/mod.rs @@ -11,12 +11,14 @@ //! The main parser interface use ast; -use codemap::{self, Span, CodeMap, FileMap}; +use codemap::CodeMap; +use syntax_pos::{self, Span, FileMap}; use errors::{Handler, ColorConfig, DiagnosticBuilder}; use parse::parser::Parser; use parse::token::InternedString; use ptr::P; use str::char_at; +use tokenstream; use std::cell::RefCell; use std::iter; @@ -160,7 +162,7 @@ pub fn parse_tts_from_source_str<'a>(name: String, source: String, cfg: ast::CrateConfig, sess: &'a ParseSess) - -> PResult<'a, Vec> { + -> PResult<'a, Vec> { let mut p = new_parser_from_source_str( sess, cfg, @@ -211,8 +213,8 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess, let end_pos = filemap.end_pos; let mut parser = tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg); - if parser.token == token::Eof && parser.span == codemap::DUMMY_SP { - parser.span = codemap::mk_sp(end_pos, end_pos); + if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP { + parser.span = syntax_pos::mk_sp(end_pos, end_pos); } parser @@ -222,7 +224,7 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess, // compiler expands into it pub fn new_parser_from_tts<'a>(sess: &'a ParseSess, cfg: ast::CrateConfig, - tts: Vec) -> Parser<'a> { + tts: Vec) -> Parser<'a> { tts_to_parser(sess, tts, cfg) } @@ -247,7 +249,7 @@ fn file_to_filemap(sess: &ParseSess, path: &Path, spanopt: Option) /// Given a filemap, produce a sequence of token-trees pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc) - -> Vec { + -> Vec { // it appears to me that the cfg doesn't matter here... indeed, // parsing tt's probably shouldn't require a parser at all. let cfg = Vec::new(); @@ -258,7 +260,7 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc) /// Given tts and cfg, produce a parser pub fn tts_to_parser<'a>(sess: &'a ParseSess, - tts: Vec, + tts: Vec, cfg: ast::CrateConfig) -> Parser<'a> { let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, None, tts); let mut p = Parser::new(sess, cfg, Box::new(trdr)); @@ -660,9 +662,9 @@ pub fn integer_lit(s: &str, #[cfg(test)] mod tests { use super::*; - use std::rc::Rc; - use codemap::{Span, BytePos, Pos, Spanned, NO_EXPANSION}; - use ast::{self, TokenTree, PatKind}; + use syntax_pos::{Span, BytePos, Pos, NO_EXPANSION}; + use codemap::Spanned; + use ast::{self, PatKind}; use abi::Abi; use attr::{first_attr_value_str_by_name, AttrMetaMethods}; use parse; @@ -670,10 +672,12 @@ mod tests { use parse::token::{str_to_ident}; use print::pprust::item_to_string; use ptr::P; + use tokenstream::{self, TokenTree}; use util::parser_testing::{string_to_tts, string_to_parser}; use util::parser_testing::{string_to_expr, string_to_item, string_to_stmt}; + use util::ThinVec; - // produce a codemap::span + // produce a syntax_pos::span fn sp(a: u32, b: u32) -> Span { Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION} } @@ -693,7 +697,7 @@ mod tests { ), }), span: sp(0, 1), - attrs: None, + attrs: ThinVec::new(), })) } @@ -716,7 +720,7 @@ mod tests { ) }), span: sp(0, 6), - attrs: None, + attrs: ThinVec::new(), })) } @@ -729,7 +733,7 @@ mod tests { #[test] fn string_to_tts_macro () { let tts = string_to_tts("macro_rules! zip (($a)=>($a))".to_string()); - let tts: &[ast::TokenTree] = &tts[..]; + let tts: &[tokenstream::TokenTree] = &tts[..]; match (tts.len(), tts.get(0), tts.get(1), tts.get(2), tts.get(3)) { ( @@ -759,7 +763,7 @@ mod tests { ) if first_delimed.delim == token::Paren && ident.name.as_str() == "a" => {}, - _ => panic!("value 3: {:?}", **first_delimed), + _ => panic!("value 3: {:?}", *first_delimed), } let tts = &second_delimed.tts[..]; match (tts.len(), tts.get(0), tts.get(1)) { @@ -770,10 +774,10 @@ mod tests { ) if second_delimed.delim == token::Paren && ident.name.as_str() == "a" => {}, - _ => panic!("value 4: {:?}", **second_delimed), + _ => panic!("value 4: {:?}", *second_delimed), } }, - _ => panic!("value 2: {:?}", **macro_delimed), + _ => panic!("value 2: {:?}", *macro_delimed), } }, _ => panic!("value: {:?}",tts), @@ -789,7 +793,7 @@ mod tests { TokenTree::Token(sp(3, 4), token::Ident(str_to_ident("a"))), TokenTree::Delimited( sp(5, 14), - Rc::new(ast::Delimited { + tokenstream::Delimited { delim: token::DelimToken::Paren, open_span: sp(5, 6), tts: vec![ @@ -798,10 +802,10 @@ mod tests { TokenTree::Token(sp(10, 13), token::Ident(str_to_ident("i32"))), ], close_span: sp(13, 14), - })), + }), TokenTree::Delimited( sp(15, 21), - Rc::new(ast::Delimited { + tokenstream::Delimited { delim: token::DelimToken::Brace, open_span: sp(15, 16), tts: vec![ @@ -809,7 +813,7 @@ mod tests { TokenTree::Token(sp(18, 19), token::Semi), ], close_span: sp(20, 21), - })) + }) ]; assert_eq!(tts, expected); @@ -832,16 +836,16 @@ mod tests { ), }), span:sp(7,8), - attrs: None, + attrs: ThinVec::new(), }))), span:sp(0,8), - attrs: None, + attrs: ThinVec::new(), })) } #[test] fn parse_stmt_1 () { assert!(string_to_stmt("b;".to_string()) == - Some(Spanned{ + Some(ast::Stmt { node: ast::StmtKind::Expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { @@ -855,8 +859,8 @@ mod tests { ), }), span: sp(0,1), - attrs: None}), - ast::DUMMY_NODE_ID), + attrs: ThinVec::new()})), + id: ast::DUMMY_NODE_ID, span: sp(0,1)})) } @@ -932,7 +936,7 @@ mod tests { } }, P(ast::Block { - stmts: vec!(Spanned{ + stmts: vec!(ast::Stmt { node: ast::StmtKind::Semi(P(ast::Expr{ id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, @@ -950,10 +954,9 @@ mod tests { ), }), span: sp(17,18), - attrs: None,}), - ast::DUMMY_NODE_ID), + attrs: ThinVec::new()})), + id: ast::DUMMY_NODE_ID, span: sp(17,19)}), - expr: None, id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Default, // no idea span: sp(15,21), @@ -992,8 +995,8 @@ mod tests { struct PatIdentVisitor { spans: Vec } - impl<'v> ::visit::Visitor<'v> for PatIdentVisitor { - fn visit_pat(&mut self, p: &'v ast::Pat) { + impl ::visit::Visitor for PatIdentVisitor { + fn visit_pat(&mut self, p: &ast::Pat) { match p.node { PatKind::Ident(_ , ref spannedident, _) => { self.spans.push(spannedident.span.clone()); diff --git a/syntex_syntax/src/parse/obsolete.rs b/syntex_syntax/src/parse/obsolete.rs index 75f1ac49..a1d7ddcd 100644 --- a/syntex_syntax/src/parse/obsolete.rs +++ b/syntex_syntax/src/parse/obsolete.rs @@ -13,7 +13,7 @@ //! //! Obsolete syntax that becomes too hard to parse can be removed. -use codemap::Span; +use syntax_pos::Span; use parse::parser; /// The specific types of unsupported syntax diff --git a/syntex_syntax/src/parse/parser.rs b/syntex_syntax/src/parse/parser.rs index 341b076e..20a54228 100644 --- a/syntex_syntax/src/parse/parser.rs +++ b/syntex_syntax/src/parse/parser.rs @@ -16,8 +16,8 @@ use ast::{Mod, Arg, Arm, Attribute, BindingMode, TraitItemKind}; use ast::Block; use ast::{BlockCheckMode, CaptureBy}; use ast::{Constness, Crate, CrateConfig}; -use ast::{Decl, DeclKind, Defaultness}; -use ast::{EMPTY_CTXT, EnumDef}; +use ast::Defaultness; +use ast::EnumDef; use ast::{Expr, ExprKind, RangeLimits}; use ast::{Field, FnDecl}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; @@ -33,14 +33,14 @@ use ast::{Stmt, StmtKind}; use ast::{VariantData, StructField}; use ast::StrStyle; use ast::SelfKind; -use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef}; +use ast::{TraitItem, TraitRef}; use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; -use attr::{ThinAttributes, ThinAttributesExt, AttributesExt}; use ast::{BinOpKind, UnOp}; use ast; -use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap}; +use codemap::{self, CodeMap, Spanned, spanned}; +use syntax_pos::{self, Span, BytePos, mk_sp}; use errors::{self, DiagnosticBuilder}; use ext::tt::macro_parser; use parse; @@ -55,6 +55,8 @@ use util::parser::{AssocOp, Fixity}; use print::pprust; use ptr::P; use parse::PResult; +use tokenstream::{self, Delimited, SequenceRepetition, TokenTree}; +use util::ThinVec; use std::collections::HashSet; use std::mem; @@ -120,7 +122,7 @@ macro_rules! maybe_whole_expr { _ => unreachable!() }; let span = $p.span; - Some($p.mk_expr(span.lo, span.hi, ExprKind::Path(None, pt), None)) + Some($p.mk_expr(span.lo, span.hi, ExprKind::Path(None, pt), ThinVec::new())) } token::Interpolated(token::NtBlock(_)) => { // FIXME: The following avoids an issue with lexical borrowck scopes, @@ -130,7 +132,7 @@ macro_rules! maybe_whole_expr { _ => unreachable!() }; let span = $p.span; - Some($p.mk_expr(span.lo, span.hi, ExprKind::Block(b), None)) + Some($p.mk_expr(span.lo, span.hi, ExprKind::Block(b), ThinVec::new())) } _ => None }; @@ -316,12 +318,12 @@ pub struct ModulePathError { pub enum LhsExpr { NotYetParsed, - AttributesParsed(ThinAttributes), + AttributesParsed(ThinVec), AlreadyParsed(P), } -impl From> for LhsExpr { - fn from(o: Option) -> Self { +impl From>> for LhsExpr { + fn from(o: Option>) -> Self { if let Some(attrs) = o { LhsExpr::AttributesParsed(attrs) } else { @@ -344,7 +346,7 @@ impl<'a> Parser<'a> { { let tok0 = rdr.real_token(); let span = tok0.sp; - let filename = if span != codemap::DUMMY_SP { + let filename = if span != syntax_pos::DUMMY_SP { Some(sess.codemap().span_to_filename(span)) } else { None }; let placeholder = TokenAndSpan { @@ -551,10 +553,6 @@ impl<'a> Parser<'a> { self.expect_one_of(edible, inedible) } - pub fn commit_stmt_expecting(&mut self, edible: token::Token) -> PResult<'a, ()> { - self.commit_stmt(&[edible], &[]) - } - /// returns the span of expr, if it was not interpolated or the span of the interpolated token fn interpolated_or_expr_span(&self, expr: PResult<'a, P>) @@ -1232,55 +1230,70 @@ impl<'a> Parser<'a> { } /// Parse the items in a trait declaration - pub fn parse_trait_items(&mut self) -> PResult<'a, Vec> { - self.parse_unspanned_seq( - &token::OpenDelim(token::Brace), - &token::CloseDelim(token::Brace), - SeqSep::none(), - |p| -> PResult<'a, TraitItem> { - maybe_whole!(no_clone_from_p p, NtTraitItem); - let mut attrs = p.parse_outer_attributes()?; - let lo = p.span.lo; - - let (name, node) = if p.eat_keyword(keywords::Type) { - let TyParam {ident, bounds, default, ..} = p.parse_ty_param()?; - p.expect(&token::Semi)?; - (ident, TraitItemKind::Type(bounds, default)) - } else if p.is_const_item() { - p.expect_keyword(keywords::Const)?; - let ident = p.parse_ident()?; - p.expect(&token::Colon)?; - let ty = p.parse_ty_sum()?; - let default = if p.check(&token::Eq) { - p.bump(); - let expr = p.parse_expr()?; - p.commit_expr_expecting(&expr, token::Semi)?; - Some(expr) - } else { - p.expect(&token::Semi)?; - None - }; - (ident, TraitItemKind::Const(ty, default)) + pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> { + maybe_whole!(no_clone_from_p self, NtTraitItem); + let mut attrs = self.parse_outer_attributes()?; + let lo = self.span.lo; + + let (name, node) = if self.eat_keyword(keywords::Type) { + let TyParam {ident, bounds, default, ..} = self.parse_ty_param()?; + self.expect(&token::Semi)?; + (ident, TraitItemKind::Type(bounds, default)) + } else if self.is_const_item() { + self.expect_keyword(keywords::Const)?; + let ident = self.parse_ident()?; + self.expect(&token::Colon)?; + let ty = self.parse_ty_sum()?; + let default = if self.check(&token::Eq) { + self.bump(); + let expr = self.parse_expr()?; + self.commit_expr_expecting(&expr, token::Semi)?; + Some(expr) + } else { + self.expect(&token::Semi)?; + None + }; + (ident, TraitItemKind::Const(ty, default)) + } else if !self.token.is_any_keyword() + && self.look_ahead(1, |t| *t == token::Not) + && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren)) + || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) { + // trait item macro. + // code copied from parse_macro_use_or_failure... abstraction! + let lo = self.span.lo; + let pth = self.parse_ident_into_path()?; + self.expect(&token::Not)?; + + // eat a matched-delimiter token tree: + let delim = self.expect_open_delim()?; + let tts = self.parse_seq_to_end(&token::CloseDelim(delim), + SeqSep::none(), + |pp| pp.parse_token_tree())?; + let m_ = Mac_ { path: pth, tts: tts }; + let m: ast::Mac = codemap::Spanned { node: m_, + span: mk_sp(lo, + self.last_span.hi) }; + if delim != token::Brace { + self.expect(&token::Semi)? + } + (keywords::Invalid.ident(), ast::TraitItemKind::Macro(m)) } else { - let (constness, unsafety, abi) = match p.parse_fn_front_matter() { + let (constness, unsafety, abi) = match self.parse_fn_front_matter() { Ok(cua) => cua, Err(e) => { loop { - match p.token { + match self.token { token::Eof => break, - token::CloseDelim(token::Brace) | token::Semi => { - p.bump(); + self.bump(); break; } - token::OpenDelim(token::Brace) => { - p.parse_token_tree()?; + self.parse_token_tree()?; break; } - - _ => p.bump() + _ => self.bump() } } @@ -1288,17 +1301,17 @@ impl<'a> Parser<'a> { } }; - let ident = p.parse_ident()?; - let mut generics = p.parse_generics()?; + let ident = self.parse_ident()?; + let mut generics = self.parse_generics()?; - let d = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ + let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... p.parse_arg_general(false) })?; - generics.where_clause = p.parse_where_clause()?; + generics.where_clause = self.parse_where_clause()?; let sig = ast::MethodSig { unsafety: unsafety, constness: constness, @@ -1307,37 +1320,47 @@ impl<'a> Parser<'a> { abi: abi, }; - let body = match p.token { - token::Semi => { - p.bump(); - debug!("parse_trait_methods(): parsing required method"); - None - } - token::OpenDelim(token::Brace) => { - debug!("parse_trait_methods(): parsing provided method"); - let (inner_attrs, body) = - p.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } + let body = match self.token { + token::Semi => { + self.bump(); + debug!("parse_trait_methods(): parsing required method"); + None + } + token::OpenDelim(token::Brace) => { + debug!("parse_trait_methods(): parsing provided method"); + let (inner_attrs, body) = + self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } - _ => { - let token_str = p.this_token_to_string(); - return Err(p.fatal(&format!("expected `;` or `{{`, found `{}`", - token_str)[..])) - } + _ => { + let token_str = self.this_token_to_string(); + return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`", + token_str)[..])) + } }; (ident, ast::TraitItemKind::Method(sig, body)) }; + Ok(TraitItem { + id: ast::DUMMY_NODE_ID, + ident: name, + attrs: attrs, + node: node, + span: mk_sp(lo, self.last_span.hi), + }) + } - Ok(TraitItem { - id: ast::DUMMY_NODE_ID, - ident: name, - attrs: attrs, - node: node, - span: mk_sp(lo, p.last_span.hi), + + /// Parse the items in a trait declaration + pub fn parse_trait_items(&mut self) -> PResult<'a, Vec> { + self.parse_unspanned_seq( + &token::OpenDelim(token::Brace), + &token::CloseDelim(token::Brace), + SeqSep::none(), + |p| -> PResult<'a, TraitItem> { + p.parse_trait_item() }) - }) } /// Parse a possibly mutable type @@ -1467,7 +1490,7 @@ impl<'a> Parser<'a> { SeqSep::none(), |p| p.parse_token_tree())?; let hi = self.span.hi; - TyKind::Mac(spanned(lo, hi, Mac_ { path: path, tts: tts, ctxt: EMPTY_CTXT })) + TyKind::Mac(spanned(lo, hi, Mac_ { path: path, tts: tts })) } else { // NAMED TYPE TyKind::Path(None, path) @@ -1676,12 +1699,12 @@ impl<'a> Parser<'a> { let lo = self.span.lo; let literal = P(self.parse_lit()?); let hi = self.last_span.hi; - let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), None); + let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new()); if minus_present { let minus_hi = self.last_span.hi; let unary = self.mk_unary(UnOp::Neg, expr); - Ok(self.mk_expr(minus_lo, minus_hi, unary, None)) + Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new())) } else { Ok(expr) } @@ -2039,13 +2062,13 @@ impl<'a> Parser<'a> { }) } - pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, - node: ExprKind, attrs: ThinAttributes) -> P { + pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: ExprKind, attrs: ThinVec) + -> P { P(Expr { id: ast::DUMMY_NODE_ID, node: node, span: mk_sp(lo, hi), - attrs: attrs, + attrs: attrs.into(), }) } @@ -2102,7 +2125,7 @@ impl<'a> Parser<'a> { } pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos, - m: Mac_, attrs: ThinAttributes) -> P { + m: Mac_, attrs: ThinVec) -> P { P(Expr { id: ast::DUMMY_NODE_ID, node: ExprKind::Mac(codemap::Spanned {node: m, span: mk_sp(lo, hi)}), @@ -2111,7 +2134,7 @@ impl<'a> Parser<'a> { }) } - pub fn mk_lit_u32(&mut self, i: u32, attrs: ThinAttributes) -> P { + pub fn mk_lit_u32(&mut self, i: u32, attrs: ThinVec) -> P { let span = &self.span; let lv_lit = P(codemap::Spanned { node: LitKind::Int(i as u64, ast::LitIntType::Unsigned(UintTy::U32)), @@ -2152,7 +2175,7 @@ impl<'a> Parser<'a> { // // Therefore, prevent sub-parser from parsing // attributes by giving them a empty "already parsed" list. - let mut attrs = None; + let mut attrs = ThinVec::new(); let lo = self.span.lo; let mut hi = self.span.hi; @@ -2164,9 +2187,7 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Paren) => { self.bump(); - let attrs = self.parse_inner_attributes()? - .into_thin_attrs() - .prepend(attrs); + attrs.extend(self.parse_inner_attributes()?); // (e) is parenthesized e // (e,) is a tuple with only one field, e @@ -2204,9 +2225,7 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Bracket) => { self.bump(); - let inner_attrs = self.parse_inner_attributes()? - .into_thin_attrs(); - attrs.update(|attrs| attrs.append(inner_attrs)); + attrs.extend(self.parse_inner_attributes()?); if self.check(&token::CloseDelim(token::Bracket)) { // Empty vector. @@ -2285,14 +2304,14 @@ impl<'a> Parser<'a> { } if self.eat_keyword(keywords::Continue) { let ex = if self.token.is_lifetime() { - let ex = ExprKind::Again(Some(Spanned{ + let ex = ExprKind::Continue(Some(Spanned{ node: self.get_lifetime(), span: self.span })); self.bump(); ex } else { - ExprKind::Again(None) + ExprKind::Continue(None) }; let hi = self.last_span.hi; return Ok(self.mk_expr(lo, hi, ex, attrs)); @@ -2348,7 +2367,7 @@ impl<'a> Parser<'a> { return Ok(self.mk_mac_expr(lo, hi, - Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT }, + Mac_ { path: pth, tts: tts }, attrs)); } if self.check(&token::OpenDelim(token::Brace)) { @@ -2363,9 +2382,7 @@ impl<'a> Parser<'a> { let mut fields = Vec::new(); let mut base = None; - let attrs = attrs.append( - self.parse_inner_attributes()? - .into_thin_attrs()); + attrs.extend(self.parse_inner_attributes()?); while self.token != token::CloseDelim(token::Brace) { if self.eat(&token::DotDot) { @@ -2432,25 +2449,24 @@ impl<'a> Parser<'a> { } fn parse_or_use_outer_attributes(&mut self, - already_parsed_attrs: Option) - -> PResult<'a, ThinAttributes> { + already_parsed_attrs: Option>) + -> PResult<'a, ThinVec> { if let Some(attrs) = already_parsed_attrs { Ok(attrs) } else { - self.parse_outer_attributes().map(|a| a.into_thin_attrs()) + self.parse_outer_attributes().map(|a| a.into()) } } /// Parse a block or unsafe block pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode, - attrs: ThinAttributes) + outer_attrs: ThinVec) -> PResult<'a, P> { - let outer_attrs = attrs; self.expect(&token::OpenDelim(token::Brace))?; - let inner_attrs = self.parse_inner_attributes()?.into_thin_attrs(); - let attrs = outer_attrs.append(inner_attrs); + let mut attrs = outer_attrs; + attrs.extend(self.parse_inner_attributes()?); let blk = self.parse_block_tail(lo, blk_mode)?; return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), attrs)); @@ -2458,7 +2474,7 @@ impl<'a> Parser<'a> { /// parse a.b or a(13) or a[4] or just a pub fn parse_dot_or_call_expr(&mut self, - already_parsed_attrs: Option) + already_parsed_attrs: Option>) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; @@ -2470,7 +2486,7 @@ impl<'a> Parser<'a> { pub fn parse_dot_or_call_expr_with(&mut self, e0: P, lo: BytePos, - attrs: ThinAttributes) + mut attrs: ThinVec) -> PResult<'a, P> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code @@ -2478,12 +2494,13 @@ impl<'a> Parser<'a> { self.parse_dot_or_call_expr_with_(e0, lo) .map(|expr| expr.map(|mut expr| { - expr.attrs.update(|a| a.prepend(attrs)); + attrs.extend::>(expr.attrs.into()); + expr.attrs = attrs; match expr.node { ExprKind::If(..) | ExprKind::IfLet(..) => { - if !expr.attrs.as_attr_slice().is_empty() { + if !expr.attrs.is_empty() { // Just point to the first attribute in there... - let span = expr.attrs.as_attr_slice()[0].span; + let span = expr.attrs[0].span; self.span_err(span, "attributes are not yet allowed on `if` \ @@ -2531,7 +2548,7 @@ impl<'a> Parser<'a> { es.insert(0, self_value); let id = spanned(ident_span.lo, ident_span.hi, ident); let nd = self.mk_method_call(id, tys, es); - self.mk_expr(lo, hi, nd, None) + self.mk_expr(lo, hi, nd, ThinVec::new()) } // Field access. _ => { @@ -2544,7 +2561,7 @@ impl<'a> Parser<'a> { let id = spanned(ident_span.lo, ident_span.hi, ident); let field = self.mk_field(self_value, id); - self.mk_expr(lo, ident_span.hi, field, None) + self.mk_expr(lo, ident_span.hi, field, ThinVec::new()) } }) } @@ -2556,7 +2573,7 @@ impl<'a> Parser<'a> { // expr? while self.eat(&token::Question) { let hi = self.last_span.hi; - e = self.mk_expr(lo, hi, ExprKind::Try(e), None); + e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new()); } // expr.f @@ -2584,7 +2601,7 @@ impl<'a> Parser<'a> { Some(n) => { let id = spanned(dot, hi, n); let field = self.mk_tup_field(e, id); - e = self.mk_expr(lo, hi, field, None); + e = self.mk_expr(lo, hi, field, ThinVec::new()); } None => { let last_span = self.last_span; @@ -2636,7 +2653,7 @@ impl<'a> Parser<'a> { hi = self.last_span.hi; let nd = self.mk_call(e, es); - e = self.mk_expr(lo, hi, nd, None); + e = self.mk_expr(lo, hi, nd, ThinVec::new()); } // expr[...] @@ -2647,7 +2664,7 @@ impl<'a> Parser<'a> { hi = self.span.hi; self.commit_expr_expecting(&ix, token::CloseDelim(token::Bracket))?; let index = self.mk_index(e, ix); - e = self.mk_expr(lo, hi, index, None) + e = self.mk_expr(lo, hi, index, ThinVec::new()) } _ => return Ok(e) } @@ -2671,13 +2688,12 @@ impl<'a> Parser<'a> { )?; let (sep, repeat) = self.parse_sep_and_kleene_op()?; let name_num = macro_parser::count_names(&seq); - return Ok(TokenTree::Sequence(mk_sp(sp.lo, seq_span.hi), - Rc::new(SequenceRepetition { - tts: seq, - separator: sep, - op: repeat, - num_captures: name_num - }))); + return Ok(TokenTree::Sequence(mk_sp(sp.lo, seq_span.hi), SequenceRepetition { + tts: seq, + separator: sep, + op: repeat, + num_captures: name_num + })); } else if self.token.is_keyword(keywords::Crate) { self.bump(); return Ok(TokenTree::Token(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar))); @@ -2720,16 +2736,17 @@ impl<'a> Parser<'a> { /// Parse an optional separator followed by a Kleene-style /// repetition token (+ or *). pub fn parse_sep_and_kleene_op(&mut self) - -> PResult<'a, (Option, ast::KleeneOp)> { - fn parse_kleene_op<'a>(parser: &mut Parser<'a>) -> PResult<'a, Option> { + -> PResult<'a, (Option, tokenstream::KleeneOp)> { + fn parse_kleene_op<'a>(parser: &mut Parser<'a>) -> + PResult<'a, Option> { match parser.token { token::BinOp(token::Star) => { parser.bump(); - Ok(Some(ast::KleeneOp::ZeroOrMore)) + Ok(Some(tokenstream::KleeneOp::ZeroOrMore)) }, token::BinOp(token::Plus) => { parser.bump(); - Ok(Some(ast::KleeneOp::OneOrMore)) + Ok(Some(tokenstream::KleeneOp::OneOrMore)) }, _ => Ok(None) } @@ -2832,12 +2849,12 @@ impl<'a> Parser<'a> { _ => {} } - Ok(TokenTree::Delimited(span, Rc::new(Delimited { + Ok(TokenTree::Delimited(span, Delimited { delim: delim, open_span: open_span, tts: tts, close_span: close_span, - }))) + })) }, _ => { // invariants: the current token is not a left-delimiter, @@ -2878,7 +2895,7 @@ impl<'a> Parser<'a> { /// Parse a prefix-unary-operator expr pub fn parse_prefix_expr(&mut self, - already_parsed_attrs: Option) + already_parsed_attrs: Option>) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; let lo = self.span.lo; @@ -2923,8 +2940,7 @@ impl<'a> Parser<'a> { let blk = self.parse_block()?; let span = blk.span; hi = span.hi; - let blk_expr = self.mk_expr(span.lo, span.hi, ExprKind::Block(blk), - None); + let blk_expr = self.mk_expr(span.lo, hi, ExprKind::Block(blk), ThinVec::new()); ExprKind::InPlace(place, blk_expr) } token::Ident(..) if self.token.is_keyword(keywords::Box) => { @@ -2944,7 +2960,7 @@ impl<'a> Parser<'a> { /// This parses an expression accounting for associativity and precedence of the operators in /// the expression. pub fn parse_assoc_expr(&mut self, - already_parsed_attrs: Option) + already_parsed_attrs: Option>) -> PResult<'a, P> { self.parse_assoc_expr_with(0, already_parsed_attrs.into()) } @@ -2997,13 +3013,13 @@ impl<'a> Parser<'a> { // Special cases: if op == AssocOp::As { let rhs = self.parse_ty()?; - lhs = self.mk_expr(lhs_span.lo, rhs.span.hi, - ExprKind::Cast(lhs, rhs), None); + let (lo, hi) = (lhs_span.lo, rhs.span.hi); + lhs = self.mk_expr(lo, hi, ExprKind::Cast(lhs, rhs), ThinVec::new()); continue } else if op == AssocOp::Colon { let rhs = self.parse_ty()?; - lhs = self.mk_expr(lhs_span.lo, rhs.span.hi, - ExprKind::Type(lhs, rhs), None); + let (lo, hi) = (lhs_span.lo, rhs.span.hi); + lhs = self.mk_expr(lo, hi, ExprKind::Type(lhs, rhs), ThinVec::new()); continue } else if op == AssocOp::DotDot || op == AssocOp::DotDotDot { // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to @@ -3029,7 +3045,7 @@ impl<'a> Parser<'a> { }; let r = try!(self.mk_range(Some(lhs), rhs, limits)); - lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None); + lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, ThinVec::new()); break } @@ -3056,6 +3072,7 @@ impl<'a> Parser<'a> { }), }?; + let (lo, hi) = (lhs_span.lo, rhs.span.hi); lhs = match op { AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor | @@ -3063,14 +3080,13 @@ impl<'a> Parser<'a> { AssocOp::Equal | AssocOp::Less | AssocOp::LessEqual | AssocOp::NotEqual | AssocOp::Greater | AssocOp::GreaterEqual => { let ast_op = op.to_ast_binop().unwrap(); - let (lhs_span, rhs_span) = (lhs_span, rhs.span); let binary = self.mk_binary(codemap::respan(cur_op_span, ast_op), lhs, rhs); - self.mk_expr(lhs_span.lo, rhs_span.hi, binary, None) + self.mk_expr(lo, hi, binary, ThinVec::new()) } AssocOp::Assign => - self.mk_expr(lhs_span.lo, rhs.span.hi, ExprKind::Assign(lhs, rhs), None), + self.mk_expr(lo, hi, ExprKind::Assign(lhs, rhs), ThinVec::new()), AssocOp::Inplace => - self.mk_expr(lhs_span.lo, rhs.span.hi, ExprKind::InPlace(lhs, rhs), None), + self.mk_expr(lo, hi, ExprKind::InPlace(lhs, rhs), ThinVec::new()), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, @@ -3084,9 +3100,8 @@ impl<'a> Parser<'a> { token::Shl => BinOpKind::Shl, token::Shr => BinOpKind::Shr, }; - let (lhs_span, rhs_span) = (lhs_span, rhs.span); let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); - self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None) + self.mk_expr(lo, hi, aopexpr, ThinVec::new()) } AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => { self.bug("As, Colon, DotDot or DotDotDot branch reached") @@ -3121,7 +3136,7 @@ impl<'a> Parser<'a> { /// Parse prefix-forms of range notation: `..expr`, `..`, `...expr` fn parse_prefix_range_expr(&mut self, - already_parsed_attrs: Option) + already_parsed_attrs: Option>) -> PResult<'a, P> { debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot); let tok = self.token.clone(); @@ -3166,7 +3181,7 @@ impl<'a> Parser<'a> { } /// Parse an 'if' or 'if let' expression ('if' token already eaten) - pub fn parse_if_expr(&mut self, attrs: ThinAttributes) -> PResult<'a, P> { + pub fn parse_if_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { if self.check_keyword(keywords::Let) { return self.parse_if_let_expr(attrs); } @@ -3184,7 +3199,7 @@ impl<'a> Parser<'a> { } /// Parse an 'if let' expression ('if' token already eaten) - pub fn parse_if_let_expr(&mut self, attrs: ThinAttributes) + pub fn parse_if_let_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.last_span.lo; self.expect_keyword(keywords::Let)?; @@ -3205,7 +3220,7 @@ impl<'a> Parser<'a> { pub fn parse_lambda_expr(&mut self, lo: BytePos, capture_clause: CaptureBy, - attrs: ThinAttributes) + attrs: ThinVec) -> PResult<'a, P> { let decl = self.parse_fn_block_decl()?; @@ -3217,9 +3232,12 @@ impl<'a> Parser<'a> { let body_expr = self.parse_expr()?; P(ast::Block { id: ast::DUMMY_NODE_ID, - stmts: vec![], span: body_expr.span, - expr: Some(body_expr), + stmts: vec![Stmt { + span: body_expr.span, + node: StmtKind::Expr(body_expr), + id: ast::DUMMY_NODE_ID, + }], rules: BlockCheckMode::Default, }) } @@ -3240,24 +3258,24 @@ impl<'a> Parser<'a> { // `else` token already eaten pub fn parse_else_expr(&mut self) -> PResult<'a, P> { if self.eat_keyword(keywords::If) { - return self.parse_if_expr(None); + return self.parse_if_expr(ThinVec::new()); } else { let blk = self.parse_block()?; - return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), None)); + return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), ThinVec::new())); } } /// Parse a 'for' .. 'in' expression ('for' token already eaten) pub fn parse_for_expr(&mut self, opt_ident: Option, span_lo: BytePos, - attrs: ThinAttributes) -> PResult<'a, P> { + mut attrs: ThinVec) -> PResult<'a, P> { // Parse: `for in ` let pat = self.parse_pat()?; self.expect_keyword(keywords::In)?; let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; - let attrs = attrs.append(iattrs.into_thin_attrs()); + attrs.extend(iattrs); let hi = self.last_span.hi; @@ -3269,13 +3287,13 @@ impl<'a> Parser<'a> { /// Parse a 'while' or 'while let' expression ('while' token already eaten) pub fn parse_while_expr(&mut self, opt_ident: Option, span_lo: BytePos, - attrs: ThinAttributes) -> PResult<'a, P> { + mut attrs: ThinVec) -> PResult<'a, P> { if self.token.is_keyword(keywords::Let) { return self.parse_while_let_expr(opt_ident, span_lo, attrs); } let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; - let attrs = attrs.append(iattrs.into_thin_attrs()); + attrs.extend(iattrs); let hi = body.span.hi; return Ok(self.mk_expr(span_lo, hi, ExprKind::While(cond, body, opt_ident), attrs)); @@ -3284,13 +3302,13 @@ impl<'a> Parser<'a> { /// Parse a 'while let' expression ('while' token already eaten) pub fn parse_while_let_expr(&mut self, opt_ident: Option, span_lo: BytePos, - attrs: ThinAttributes) -> PResult<'a, P> { + mut attrs: ThinVec) -> PResult<'a, P> { self.expect_keyword(keywords::Let)?; let pat = self.parse_pat()?; self.expect(&token::Eq)?; let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; - let attrs = attrs.append(iattrs.into_thin_attrs()); + attrs.extend(iattrs); let hi = body.span.hi; return Ok(self.mk_expr(span_lo, hi, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); } @@ -3298,15 +3316,15 @@ impl<'a> Parser<'a> { // parse `loop {...}`, `loop` token already eaten pub fn parse_loop_expr(&mut self, opt_ident: Option, span_lo: BytePos, - attrs: ThinAttributes) -> PResult<'a, P> { + mut attrs: ThinVec) -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; - let attrs = attrs.append(iattrs.into_thin_attrs()); + attrs.extend(iattrs); let hi = body.span.hi; Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) } // `match` token already eaten - fn parse_match_expr(&mut self, attrs: ThinAttributes) -> PResult<'a, P> { + fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { let match_span = self.last_span; let lo = self.last_span.lo; let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, @@ -3318,8 +3336,8 @@ impl<'a> Parser<'a> { } return Err(e) } - let attrs = attrs.append( - self.parse_inner_attributes()?.into_thin_attrs()); + attrs.extend(self.parse_inner_attributes()?); + let mut arms: Vec = Vec::new(); while self.token != token::CloseDelim(token::Brace) { match self.parse_arm() { @@ -3392,7 +3410,7 @@ impl<'a> Parser<'a> { /// Parse an expression, subject to the given restrictions pub fn parse_expr_res(&mut self, r: Restrictions, - already_parsed_attrs: Option) + already_parsed_attrs: Option>) -> PResult<'a, P> { self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs)) } @@ -3500,7 +3518,7 @@ impl<'a> Parser<'a> { } /// Parse the fields of a struct-like pattern - fn parse_pat_fields(&mut self) -> PResult<'a, (Vec> , bool)> { + fn parse_pat_fields(&mut self) -> PResult<'a, (Vec>, bool)> { let mut fields = Vec::new(); let mut etc = false; let mut first = true; @@ -3570,9 +3588,9 @@ impl<'a> Parser<'a> { }; fields.push(codemap::Spanned { span: mk_sp(lo, hi), - node: ast::FieldPat { ident: fieldname, - pat: subpat, - is_shorthand: is_shorthand }}); + node: ast::FieldPat { ident: fieldname, + pat: subpat, + is_shorthand: is_shorthand }}); } return Ok((fields, etc)); } @@ -3590,7 +3608,7 @@ impl<'a> Parser<'a> { (None, self.parse_path(PathStyle::Expr)?) }; let hi = self.last_span.hi; - Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), None)) + Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new())) } else { self.parse_pat_literal_maybe_minus() } @@ -3661,9 +3679,9 @@ impl<'a> Parser<'a> { let tts = self.parse_seq_to_end( &token::CloseDelim(delim), SeqSep::none(), |p| p.parse_token_tree())?; - let mac = Mac_ { path: path, tts: tts, ctxt: EMPTY_CTXT }; + let mac = Mac_ { path: path, tts: tts }; pat = PatKind::Mac(codemap::Spanned {node: mac, - span: mk_sp(lo, self.last_span.hi)}); + span: mk_sp(lo, self.last_span.hi)}); } else { // Parse ident @ pat // This can give false positives and parse nullary enums, @@ -3685,7 +3703,8 @@ impl<'a> Parser<'a> { token::DotDotDot => { // Parse range let hi = self.last_span.hi; - let begin = self.mk_expr(lo, hi, ExprKind::Path(qself, path), None); + let begin = + self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()); self.bump(); let end = self.parse_pat_range_end()?; pat = PatKind::Range(begin, end); @@ -3715,12 +3734,7 @@ impl<'a> Parser<'a> { pat = PatKind::TupleStruct(path, fields, ddpos) } _ => { - pat = match qself { - // Parse qualified path - Some(qself) => PatKind::QPath(qself, path), - // Parse nullary enum - None => PatKind::Path(path) - }; + pat = PatKind::Path(qself, path); } } } @@ -3785,7 +3799,7 @@ impl<'a> Parser<'a> { } /// Parse a local variable declaration - fn parse_local(&mut self, attrs: ThinAttributes) -> PResult<'a, P> { + fn parse_local(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.span.lo; let pat = self.parse_pat()?; @@ -3804,13 +3818,6 @@ impl<'a> Parser<'a> { })) } - /// Parse a "let" stmt - fn parse_let(&mut self, attrs: ThinAttributes) -> PResult<'a, P> { - let lo = self.span.lo; - let local = self.parse_local(attrs)?; - Ok(P(spanned(lo, self.last_span.hi, DeclKind::Local(local)))) - } - /// Parse a structure field fn parse_name_and_ty(&mut self, pr: Visibility, attrs: Vec ) -> PResult<'a, StructField> { @@ -3923,12 +3930,12 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - Ok(Some(if self.check_keyword(keywords::Let) { - self.expect_keyword(keywords::Let)?; - let decl = self.parse_let(attrs.into_thin_attrs())?; - let hi = decl.span.hi; - let stmt = StmtKind::Decl(decl, ast::DUMMY_NODE_ID); - spanned(lo, hi, stmt) + Ok(Some(if self.eat_keyword(keywords::Let) { + Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Local(self.parse_local(attrs.into())?), + span: mk_sp(lo, self.last_span.hi), + } } else if self.token.is_ident() && !self.token.is_any_keyword() && self.look_ahead(1, |t| *t == token::Not) { @@ -3979,9 +3986,12 @@ impl<'a> Parser<'a> { }; if id.name == keywords::Invalid.name() { - let mac = P(spanned(lo, hi, Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })); - let stmt = StmtKind::Mac(mac, style, attrs.into_thin_attrs()); - spanned(lo, hi, stmt) + let mac = spanned(lo, hi, Mac_ { path: pth, tts: tts }); + Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Mac(P((mac, style, attrs.into()))), + span: mk_sp(lo, hi), + } } else { // if it has a special ident, it's definitely an item // @@ -3995,25 +4005,28 @@ impl<'a> Parser<'a> { followed by a semicolon"); } } - spanned(lo, hi, StmtKind::Decl( - P(spanned(lo, hi, DeclKind::Item( + Stmt { + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, hi), + node: StmtKind::Item({ self.mk_item( lo, hi, id /*id is good here*/, - ItemKind::Mac(spanned(lo, hi, - Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })), - Visibility::Inherited, attrs)))), - ast::DUMMY_NODE_ID)) + ItemKind::Mac(spanned(lo, hi, Mac_ { path: pth, tts: tts })), + Visibility::Inherited, + attrs) + }), + } } } else { // FIXME: Bad copy of attrs let restrictions = self.restrictions | Restrictions::NO_NONINLINE_MOD; match self.with_res(restrictions, |this| this.parse_item_(attrs.clone(), false, true))? { - Some(i) => { - let hi = i.span.hi; - let decl = P(spanned(lo, hi, DeclKind::Item(i))); - spanned(lo, hi, StmtKind::Decl(decl, ast::DUMMY_NODE_ID)) - } + Some(i) => Stmt { + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, i.span.hi), + node: StmtKind::Item(i), + }, None => { let unused_attrs = |attrs: &[_], s: &mut Self| { if attrs.len() > 0 { @@ -4036,10 +4049,12 @@ impl<'a> Parser<'a> { // Remainder are line-expr stmts. let e = self.parse_expr_res( - Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into_thin_attrs()))?; - let hi = e.span.hi; - let stmt = StmtKind::Expr(e, ast::DUMMY_NODE_ID); - spanned(lo, hi, stmt) + Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into()))?; + Stmt { + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, e.span.hi), + node: StmtKind::Expr(e), + } } } })) @@ -4082,10 +4097,9 @@ impl<'a> Parser<'a> { /// Precondition: already parsed the '{'. fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P> { let mut stmts = vec![]; - let mut expr = None; while !self.eat(&token::CloseDelim(token::Brace)) { - let Spanned {node, span} = if let Some(s) = self.parse_stmt_() { + let Stmt {node, span, ..} = if let Some(s) = self.parse_stmt_() { s } else if self.token == token::Eof { break; @@ -4093,69 +4107,23 @@ impl<'a> Parser<'a> { // Found only `;` or `}`. continue; }; + match node { - StmtKind::Expr(e, _) => { - self.handle_expression_like_statement(e, span, &mut stmts, &mut expr)?; - } - StmtKind::Mac(mac, MacStmtStyle::NoBraces, attrs) => { - // statement macro without braces; might be an - // expr depending on whether a semicolon follows - match self.token { - token::Semi => { - stmts.push(Spanned { - node: StmtKind::Mac(mac, MacStmtStyle::Semicolon, attrs), - span: mk_sp(span.lo, self.span.hi), - }); - self.bump(); - } - _ => { - let e = self.mk_mac_expr(span.lo, span.hi, - mac.and_then(|m| m.node), - None); - let lo = e.span.lo; - let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; - let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; - self.handle_expression_like_statement( - e, - span, - &mut stmts, - &mut expr)?; - } - } + StmtKind::Expr(e) => { + self.handle_expression_like_statement(e, span, &mut stmts)?; } - StmtKind::Mac(m, style, attrs) => { - // statement macro; might be an expr - match self.token { - token::Semi => { - stmts.push(Spanned { - node: StmtKind::Mac(m, MacStmtStyle::Semicolon, attrs), - span: mk_sp(span.lo, self.span.hi), - }); - self.bump(); - } - token::CloseDelim(token::Brace) => { - // if a block ends in `m!(arg)` without - // a `;`, it must be an expr - expr = Some(self.mk_mac_expr(span.lo, span.hi, - m.and_then(|x| x.node), - attrs)); - } - _ => { - stmts.push(Spanned { - node: StmtKind::Mac(m, style, attrs), - span: span - }); - } - } + StmtKind::Mac(mac) => { + self.handle_macro_in_block(mac.unwrap(), span, &mut stmts)?; } _ => { // all other kinds of statements: let mut hi = span.hi; if classify::stmt_ends_with_semi(&node) { - self.commit_stmt_expecting(token::Semi)?; + self.commit_stmt(&[token::Semi], &[])?; hi = self.last_span.hi; } - stmts.push(Spanned { + stmts.push(Stmt { + id: ast::DUMMY_NODE_ID, node: node, span: mk_sp(span.lo, hi) }); @@ -4165,18 +4133,64 @@ impl<'a> Parser<'a> { Ok(P(ast::Block { stmts: stmts, - expr: expr, id: ast::DUMMY_NODE_ID, rules: s, span: mk_sp(lo, self.last_span.hi), })) } + fn handle_macro_in_block(&mut self, + (mac, style, attrs): (ast::Mac, MacStmtStyle, ThinVec), + span: Span, + stmts: &mut Vec) + -> PResult<'a, ()> { + if style == MacStmtStyle::NoBraces { + // statement macro without braces; might be an + // expr depending on whether a semicolon follows + match self.token { + token::Semi => { + stmts.push(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Mac(P((mac, MacStmtStyle::Semicolon, attrs))), + span: mk_sp(span.lo, self.span.hi), + }); + self.bump(); + } + _ => { + let e = self.mk_mac_expr(span.lo, span.hi, mac.node, ThinVec::new()); + let lo = e.span.lo; + let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; + let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; + self.handle_expression_like_statement(e, span, stmts)?; + } + } + } else { + // statement macro; might be an expr + match self.token { + token::Semi => { + stmts.push(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Mac(P((mac, MacStmtStyle::Semicolon, attrs))), + span: mk_sp(span.lo, self.span.hi), + }); + self.bump(); + } + _ => { + stmts.push(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Mac(P((mac, style, attrs))), + span: span + }); + } + } + } + Ok(()) + } + fn handle_expression_like_statement(&mut self, e: P, span: Span, - stmts: &mut Vec, - last_block_expr: &mut Option>) + stmts: &mut Vec) -> PResult<'a, ()> { // expression without semicolon if classify::expr_requires_semi_to_be_stmt(&e) { @@ -4197,15 +4211,16 @@ impl<'a> Parser<'a> { hi: self.last_span.hi, expn_id: span.expn_id, }; - stmts.push(Spanned { - node: StmtKind::Semi(e, ast::DUMMY_NODE_ID), + stmts.push(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Semi(e), span: span_with_semi, }); } - token::CloseDelim(token::Brace) => *last_block_expr = Some(e), _ => { - stmts.push(Spanned { - node: StmtKind::Expr(e, ast::DUMMY_NODE_ID), + stmts.push(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Expr(e), span: span }); } @@ -4913,10 +4928,10 @@ impl<'a> Parser<'a> { let tts = self.parse_seq_to_end(&token::CloseDelim(delim), SeqSep::none(), |p| p.parse_token_tree())?; - let m_ = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT }; + let m_ = Mac_ { path: pth, tts: tts }; let m: ast::Mac = codemap::Spanned { node: m_, - span: mk_sp(lo, - self.last_span.hi) }; + span: mk_sp(lo, + self.last_span.hi) }; if delim != token::Brace { self.expect(&token::Semi)? } @@ -4940,7 +4955,6 @@ impl<'a> Parser<'a> { /// Parse trait Foo { ... } fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> { - let ident = self.parse_ident()?; let mut tps = self.parse_generics()?; @@ -5255,7 +5269,7 @@ impl<'a> Parser<'a> { return Err(self.fatal(&format!("expected item, found `{}`", token_str))); } - let hi = if self.span == codemap::DUMMY_SP { + let hi = if self.span == syntax_pos::DUMMY_SP { inner_lo } else { self.last_span.hi @@ -5999,10 +6013,10 @@ impl<'a> Parser<'a> { SeqSep::none(), |p| p.parse_token_tree())?; // single-variant-enum... : - let m = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT }; + let m = Mac_ { path: pth, tts: tts }; let m: ast::Mac = codemap::Spanned { node: m, - span: mk_sp(mac_lo, - self.last_span.hi) }; + span: mk_sp(mac_lo, + self.last_span.hi) }; if delim != token::Brace { if !self.eat(&token::Semi) { diff --git a/syntex_syntax/src/parse/token.rs b/syntex_syntax/src/parse/token.rs index 47de32ed..8376d281 100644 --- a/syntex_syntax/src/parse/token.rs +++ b/syntex_syntax/src/parse/token.rs @@ -19,6 +19,7 @@ use ext::mtwt; use ptr::P; use util::interner::{RcStr, StrInterner}; use util::interner; +use tokenstream; use serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; @@ -338,7 +339,7 @@ pub enum Nonterminal { /// Stuff inside brackets for attributes NtMeta(P), NtPath(Box), - NtTT(P), // needs P'ed to break a circularity + NtTT(P), // needs P'ed to break a circularity // These are not exposed to macros, but are used by quasiquote. NtArm(ast::Arm), NtImplItem(P), diff --git a/syntex_syntax/src/print/pprust.rs b/syntex_syntax/src/print/pprust.rs index a2ee5bf6..94b71661 100644 --- a/syntex_syntax/src/print/pprust.rs +++ b/syntex_syntax/src/print/pprust.rs @@ -11,14 +11,14 @@ pub use self::AnnNode::*; use abi::{self, Abi}; -use ast::{self, TokenTree, BlockCheckMode, PatKind}; +use ast::{self, BlockCheckMode, PatKind}; use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; -use attr::ThinAttributesExt; use util::parser::AssocOp; use attr; use attr::{AttrMetaMethods, AttributeMethods}; -use codemap::{self, CodeMap, BytePos}; +use codemap::{self, CodeMap}; +use syntax_pos::{self, BytePos}; use errors; use parse::token::{self, keywords, BinOpToken, Token, InternedString}; use parse::lexer::comments; @@ -28,6 +28,7 @@ use print::pp::{Breaks, eof}; use print::pp::Breaks::{Consistent, Inconsistent}; use ptr::P; use std_inject; +use tokenstream::{self, TokenTree}; use std::ascii; use std::io::{self, Write, Read}; @@ -330,11 +331,11 @@ pub fn lifetime_to_string(e: &ast::Lifetime) -> String { to_string(|s| s.print_lifetime(e)) } -pub fn tt_to_string(tt: &ast::TokenTree) -> String { +pub fn tt_to_string(tt: &tokenstream::TokenTree) -> String { to_string(|s| s.print_tt(tt)) } -pub fn tts_to_string(tts: &[ast::TokenTree]) -> String { +pub fn tts_to_string(tts: &[tokenstream::TokenTree]) -> String { to_string(|s| s.print_tts(tts)) } @@ -842,11 +843,11 @@ impl<'a> State<'a> { self.end() // close the head-box } - pub fn bclose_(&mut self, span: codemap::Span, + pub fn bclose_(&mut self, span: syntax_pos::Span, indented: usize) -> io::Result<()> { self.bclose_maybe_open(span, indented, true) } - pub fn bclose_maybe_open(&mut self, span: codemap::Span, + pub fn bclose_maybe_open(&mut self, span: syntax_pos::Span, indented: usize, close_box: bool) -> io::Result<()> { try!(self.maybe_print_comment(span.hi)); try!(self.break_offset_if_not_bol(1, -(indented as isize))); @@ -856,7 +857,7 @@ impl<'a> State<'a> { } Ok(()) } - pub fn bclose(&mut self, span: codemap::Span) -> io::Result<()> { + pub fn bclose(&mut self, span: syntax_pos::Span) -> io::Result<()> { self.bclose_(span, INDENT_UNIT) } @@ -900,7 +901,7 @@ impl<'a> State<'a> { mut op: F, mut get_span: G) -> io::Result<()> where F: FnMut(&mut State, &T) -> io::Result<()>, - G: FnMut(&T) -> codemap::Span, + G: FnMut(&T) -> syntax_pos::Span, { try!(self.rbox(0, b)); let len = elts.len(); @@ -1337,7 +1338,7 @@ impl<'a> State<'a> { if comma { try!(self.word_space(",")) } - try!(self.print_lifetime_def(lifetime_def)); + try!(self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)); comma = true; } try!(word(&mut self.s, ">")); @@ -1352,7 +1353,7 @@ impl<'a> State<'a> { pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef, generics: &ast::Generics, ident: ast::Ident, - span: codemap::Span, + span: syntax_pos::Span, visibility: &ast::Visibility) -> io::Result<()> { try!(self.head(&visibility_qualified(visibility, "enum"))); try!(self.print_ident(ident)); @@ -1364,7 +1365,7 @@ impl<'a> State<'a> { pub fn print_variants(&mut self, variants: &[ast::Variant], - span: codemap::Span) -> io::Result<()> { + span: syntax_pos::Span) -> io::Result<()> { try!(self.bopen()); for v in variants { try!(self.space_if_not_bol()); @@ -1393,7 +1394,7 @@ impl<'a> State<'a> { struct_def: &ast::VariantData, generics: &ast::Generics, ident: ast::Ident, - span: codemap::Span, + span: syntax_pos::Span, print_finalizer: bool) -> io::Result<()> { try!(self.print_ident(ident)); try!(self.print_generics(generics)); @@ -1445,7 +1446,7 @@ impl<'a> State<'a> { /// appropriate macro, transcribe back into the grammar we just parsed from, /// and then pretty-print the resulting AST nodes (so, e.g., we print /// expression arguments as expressions). It can be done! I think. - pub fn print_tt(&mut self, tt: &ast::TokenTree) -> io::Result<()> { + pub fn print_tt(&mut self, tt: &tokenstream::TokenTree) -> io::Result<()> { match *tt { TokenTree::Token(_, ref tk) => { try!(word(&mut self.s, &token_to_string(tk))); @@ -1476,14 +1477,14 @@ impl<'a> State<'a> { None => {}, } match seq.op { - ast::KleeneOp::ZeroOrMore => word(&mut self.s, "*"), - ast::KleeneOp::OneOrMore => word(&mut self.s, "+"), + tokenstream::KleeneOp::ZeroOrMore => word(&mut self.s, "*"), + tokenstream::KleeneOp::OneOrMore => word(&mut self.s, "+"), } } } } - pub fn print_tts(&mut self, tts: &[ast::TokenTree]) -> io::Result<()> { + pub fn print_tts(&mut self, tts: &[tokenstream::TokenTree]) -> io::Result<()> { try!(self.ibox(0)); for (i, tt) in tts.iter().enumerate() { if i != 0 { @@ -1550,6 +1551,17 @@ impl<'a> State<'a> { try!(self.print_associated_type(ti.ident, Some(bounds), default.as_ref().map(|ty| &**ty))); } + ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => { + // code copied from ItemKind::Mac: + self.print_path(&node.path, false, 0)?; + word(&mut self.s, "! ")?; + self.cbox(INDENT_UNIT)?; + self.popen()?; + self.print_tts(&node.tts[..])?; + self.pclose()?; + word(&mut self.s, ";")?; + self.end()? + } } self.ann.post(self, NodeSubItem(ti.id)) } @@ -1593,21 +1605,40 @@ impl<'a> State<'a> { pub fn print_stmt(&mut self, st: &ast::Stmt) -> io::Result<()> { try!(self.maybe_print_comment(st.span.lo)); match st.node { - ast::StmtKind::Decl(ref decl, _) => { - try!(self.print_decl(&decl)); + ast::StmtKind::Local(ref loc) => { + try!(self.print_outer_attributes(&loc.attrs)); + try!(self.space_if_not_bol()); + try!(self.ibox(INDENT_UNIT)); + try!(self.word_nbsp("let")); + + try!(self.ibox(INDENT_UNIT)); + try!(self.print_local_decl(&loc)); + try!(self.end()); + if let Some(ref init) = loc.init { + try!(self.nbsp()); + try!(self.word_space("=")); + try!(self.print_expr(&init)); + } + try!(word(&mut self.s, ";")); + self.end()?; } - ast::StmtKind::Expr(ref expr, _) => { + ast::StmtKind::Item(ref item) => self.print_item(&item)?, + ast::StmtKind::Expr(ref expr) => { try!(self.space_if_not_bol()); try!(self.print_expr_outer_attr_style(&expr, false)); + if parse::classify::expr_requires_semi_to_be_stmt(expr) { + try!(word(&mut self.s, ";")); + } } - ast::StmtKind::Semi(ref expr, _) => { + ast::StmtKind::Semi(ref expr) => { try!(self.space_if_not_bol()); try!(self.print_expr_outer_attr_style(&expr, false)); try!(word(&mut self.s, ";")); } - ast::StmtKind::Mac(ref mac, style, ref attrs) => { + ast::StmtKind::Mac(ref mac) => { + let (ref mac, style, ref attrs) = **mac; try!(self.space_if_not_bol()); - try!(self.print_outer_attributes(attrs.as_attr_slice())); + try!(self.print_outer_attributes(&attrs)); let delim = match style { ast::MacStmtStyle::Braces => token::Brace, _ => token::Paren @@ -1619,9 +1650,6 @@ impl<'a> State<'a> { } } } - if parse::classify::stmt_ends_with_semi(&st.node) { - try!(word(&mut self.s, ";")); - } self.maybe_print_trailing_comment(st.span, None) } @@ -1665,17 +1693,17 @@ impl<'a> State<'a> { try!(self.print_inner_attributes(attrs)); - for st in &blk.stmts { - try!(self.print_stmt(st)); - } - match blk.expr { - Some(ref expr) => { - try!(self.space_if_not_bol()); - try!(self.print_expr_outer_attr_style(&expr, false)); - try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))); + for (i, st) in blk.stmts.iter().enumerate() { + match st.node { + ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => { + try!(self.space_if_not_bol()); + try!(self.print_expr_outer_attr_style(&expr, false)); + try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))); + } + _ => try!(self.print_stmt(st)), } - _ => () } + try!(self.bclose_maybe_open(blk.span, indented, close_box)); self.ann.post(self, NodeBlock(blk)) } @@ -1947,7 +1975,7 @@ impl<'a> State<'a> { is_inline: bool) -> io::Result<()> { try!(self.maybe_print_comment(expr.span.lo)); - let attrs = expr.attrs.as_attr_slice(); + let attrs = &expr.attrs; if is_inline { try!(self.print_outer_attributes_inline(attrs)); } else { @@ -2084,24 +2112,21 @@ impl<'a> State<'a> { _ => false }; - if !default_return || !body.stmts.is_empty() || body.expr.is_none() { - try!(self.print_block_unclosed(&body)); - } else { - // we extract the block, so as not to create another set of boxes - let i_expr = body.expr.as_ref().unwrap(); - match i_expr.node { - ast::ExprKind::Block(ref blk) => { - try!(self.print_block_unclosed_with_attrs( - &blk, - i_expr.attrs.as_attr_slice())); - } - _ => { + match body.stmts.last().map(|stmt| &stmt.node) { + Some(&ast::StmtKind::Expr(ref i_expr)) if default_return && + body.stmts.len() == 1 => { + // we extract the block, so as not to create another set of boxes + if let ast::ExprKind::Block(ref blk) = i_expr.node { + try!(self.print_block_unclosed_with_attrs(&blk, &i_expr.attrs)); + } else { // this is a bare expression try!(self.print_expr(&i_expr)); try!(self.end()); // need to close a box } } + _ => try!(self.print_block_unclosed(&body)), } + // a box will be closed by print_expr, but we didn't want an overall // wrapper so we closed the corresponding opening. so create an // empty box to satisfy the close. @@ -2170,7 +2195,7 @@ impl<'a> State<'a> { try!(space(&mut self.s)); } } - ast::ExprKind::Again(opt_ident) => { + ast::ExprKind::Continue(opt_ident) => { try!(word(&mut self.s, "continue")); try!(space(&mut self.s)); if let Some(ident) = opt_ident { @@ -2278,29 +2303,6 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_decl(&mut self, decl: &ast::Decl) -> io::Result<()> { - try!(self.maybe_print_comment(decl.span.lo)); - match decl.node { - ast::DeclKind::Local(ref loc) => { - try!(self.print_outer_attributes(loc.attrs.as_attr_slice())); - try!(self.space_if_not_bol()); - try!(self.ibox(INDENT_UNIT)); - try!(self.word_nbsp("let")); - - try!(self.ibox(INDENT_UNIT)); - try!(self.print_local_decl(&loc)); - try!(self.end()); - if let Some(ref init) = loc.init { - try!(self.nbsp()); - try!(self.word_space("=")); - try!(self.print_expr(&init)); - } - self.end() - } - ast::DeclKind::Item(ref item) => self.print_item(&item) - } - } - pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> { try!(word(&mut self.s, &ident.name.as_str())); self.ann.post(self, NodeIdent(&ident)) @@ -2483,10 +2485,10 @@ impl<'a> State<'a> { } try!(self.pclose()); } - PatKind::Path(ref path) => { + PatKind::Path(None, ref path) => { try!(self.print_path(path, true, 0)); } - PatKind::QPath(ref qself, ref path) => { + PatKind::Path(Some(ref qself), ref path) => { try!(self.print_qpath(path, qself, false)); } PatKind::Struct(ref path, ref fields, etc) => { @@ -2747,16 +2749,20 @@ impl<'a> State<'a> { self.print_name(lifetime.name) } - pub fn print_lifetime_def(&mut self, - lifetime: &ast::LifetimeDef) - -> io::Result<()> + pub fn print_lifetime_bounds(&mut self, + lifetime: &ast::Lifetime, + bounds: &[ast::Lifetime]) + -> io::Result<()> { - try!(self.print_lifetime(&lifetime.lifetime)); - let mut sep = ":"; - for v in &lifetime.bounds { - try!(word(&mut self.s, sep)); - try!(self.print_lifetime(v)); - sep = "+"; + try!(self.print_lifetime(lifetime)); + if !bounds.is_empty() { + try!(word(&mut self.s, ": ")); + for (i, bound) in bounds.iter().enumerate() { + if i != 0 { + try!(word(&mut self.s, " + ")); + } + try!(self.print_lifetime(bound)); + } } Ok(()) } @@ -2779,8 +2785,8 @@ impl<'a> State<'a> { try!(self.commasep(Inconsistent, &ints[..], |s, &idx| { if idx < generics.lifetimes.len() { - let lifetime = &generics.lifetimes[idx]; - s.print_lifetime_def(lifetime) + let lifetime_def = &generics.lifetimes[idx]; + s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds) } else { let idx = idx - generics.lifetimes.len(); let param = &generics.ty_params[idx]; @@ -2831,16 +2837,7 @@ impl<'a> State<'a> { ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime, ref bounds, ..}) => { - try!(self.print_lifetime(lifetime)); - try!(word(&mut self.s, ":")); - - for (i, bound) in bounds.iter().enumerate() { - try!(self.print_lifetime(bound)); - - if i != 0 { - try!(word(&mut self.s, ":")); - } - } + try!(self.print_lifetime_bounds(lifetime, bounds)); } ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => { try!(self.print_path(path, false, 0)); @@ -2999,7 +2996,7 @@ impl<'a> State<'a> { self.end() } - pub fn maybe_print_trailing_comment(&mut self, span: codemap::Span, + pub fn maybe_print_trailing_comment(&mut self, span: syntax_pos::Span, next_pos: Option) -> io::Result<()> { let cm = match self.cm { @@ -3104,6 +3101,7 @@ mod tests { use ast; use codemap; use parse::token; + use syntax_pos; #[test] fn test_fun_to_string() { @@ -3111,7 +3109,7 @@ mod tests { let decl = ast::FnDecl { inputs: Vec::new(), - output: ast::FunctionRetTy::Default(codemap::DUMMY_SP), + output: ast::FunctionRetTy::Default(syntax_pos::DUMMY_SP), variadic: false }; let generics = ast::Generics::default(); @@ -3125,7 +3123,7 @@ mod tests { fn test_variant_to_string() { let ident = token::str_to_ident("principal_skinner"); - let var = codemap::respan(codemap::DUMMY_SP, ast::Variant_ { + let var = codemap::respan(syntax_pos::DUMMY_SP, ast::Variant_ { name: ident, attrs: Vec::new(), // making this up as I go.... ? diff --git a/syntex_syntax/src/show_span.rs b/syntex_syntax/src/show_span.rs index 5e3cd077..928ffb20 100644 --- a/syntex_syntax/src/show_span.rs +++ b/syntex_syntax/src/show_span.rs @@ -44,7 +44,7 @@ struct ShowSpanVisitor<'a> { mode: Mode, } -impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> { +impl<'a> Visitor for ShowSpanVisitor<'a> { fn visit_expr(&mut self, e: &ast::Expr) { if let Mode::Expression = self.mode { self.span_diagnostic.span_warn(e.span, "expression"); diff --git a/syntex_syntax/src/std_inject.rs b/syntex_syntax/src/std_inject.rs index 8834c026..d1454ab0 100644 --- a/syntex_syntax/src/std_inject.rs +++ b/syntex_syntax/src/std_inject.rs @@ -10,8 +10,8 @@ use ast; use attr; -use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute}; -use codemap; +use syntax_pos::{DUMMY_SP, Span}; +use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute}; use parse::token::{intern, InternedString, keywords}; use parse::{token, ParseSess}; use ptr::P; diff --git a/syntex_syntax/src/test.rs b/syntex_syntax/src/test.rs index ca6ed76d..0a60b7fd 100644 --- a/syntex_syntax/src/test.rs +++ b/syntex_syntax/src/test.rs @@ -12,6 +12,7 @@ #![allow(dead_code)] #![allow(unused_imports)] + use self::HasTestSignature::*; use std::iter; @@ -20,9 +21,12 @@ use std::mem; use std::vec; use attr::AttrMetaMethods; use attr; -use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute}; -use codemap; +use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; +use std::rc::Rc; + +use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute}; use errors; +use errors::snippet::{RenderedLine, SnippetData}; use config; use entry::{self, EntryPointType}; use ext::base::{ExtCtxt, DummyMacroLoader}; @@ -474,7 +478,7 @@ fn mk_main(cx: &mut TestCtxt) -> P { let main_attr = ecx.attribute(sp, main_meta); // pub fn main() { ... } let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![])); - let main_body = ecx.block_all(sp, vec![call_test_main], None); + let main_body = ecx.block(sp, vec![call_test_main]); let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], main_ret_ty), ast::Unsafety::Normal, ast::Constness::NotConst, @@ -604,10 +608,10 @@ fn mk_test_descs(cx: &TestCtxt) -> P { mk_test_desc_and_fn_rec(cx, test) }).collect()), span: DUMMY_SP, - attrs: None, + attrs: ast::ThinVec::new(), })), span: DUMMY_SP, - attrs: None, + attrs: ast::ThinVec::new(), }) } diff --git a/syntex_syntax/src/tokenstream.rs b/syntex_syntax/src/tokenstream.rs new file mode 100644 index 00000000..35377d14 --- /dev/null +++ b/syntex_syntax/src/tokenstream.rs @@ -0,0 +1,210 @@ +// Copyright 2012-2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Token Trees +//! TokenTrees are syntactic forms for dealing with tokens. The description below is +//! more complete; in short a TokenTree is a single token, a delimited sequence of token +//! trees, or a sequence with repetition for list splicing as part of macro expansion. + +use ast::{AttrStyle}; +use codemap::{Span}; +use ext::base; +use ext::tt::macro_parser; +use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; +use parse::lexer; +use parse::token; + +/// A delimited sequence of token trees +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct Delimited { + /// The type of delimiter + pub delim: token::DelimToken, + /// The span covering the opening delimiter + pub open_span: Span, + /// The delimited sequence of token trees + pub tts: Vec, + /// The span covering the closing delimiter + pub close_span: Span, +} + +impl Delimited { + /// Returns the opening delimiter as a token. + pub fn open_token(&self) -> token::Token { + token::OpenDelim(self.delim) + } + + /// Returns the closing delimiter as a token. + pub fn close_token(&self) -> token::Token { + token::CloseDelim(self.delim) + } + + /// Returns the opening delimiter as a token tree. + pub fn open_tt(&self) -> TokenTree { + TokenTree::Token(self.open_span, self.open_token()) + } + + /// Returns the closing delimiter as a token tree. + pub fn close_tt(&self) -> TokenTree { + TokenTree::Token(self.close_span, self.close_token()) + } +} + +/// A sequence of token trees +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct SequenceRepetition { + /// The sequence of token trees + pub tts: Vec, + /// The optional separator + pub separator: Option, + /// Whether the sequence can be repeated zero (*), or one or more times (+) + pub op: KleeneOp, + /// The number of `MatchNt`s that appear in the sequence (and subsequences) + pub num_captures: usize, +} + +/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) +/// for token sequences. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum KleeneOp { + ZeroOrMore, + OneOrMore, +} + +/// When the main rust parser encounters a syntax-extension invocation, it +/// parses the arguments to the invocation as a token-tree. This is a very +/// loose structure, such that all sorts of different AST-fragments can +/// be passed to syntax extensions using a uniform type. +/// +/// If the syntax extension is an MBE macro, it will attempt to match its +/// LHS token tree against the provided token tree, and if it finds a +/// match, will transcribe the RHS token tree, splicing in any captured +/// macro_parser::matched_nonterminals into the `SubstNt`s it finds. +/// +/// The RHS of an MBE macro is the only place `SubstNt`s are substituted. +/// Nothing special happens to misnamed or misplaced `SubstNt`s. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum TokenTree { + /// A single token + Token(Span, token::Token), + /// A delimited sequence of token trees + Delimited(Span, Delimited), + + // This only makes sense in MBE macros. + + /// A kleene-style repetition sequence with a span + // FIXME(eddyb) #12938 Use DST. + Sequence(Span, SequenceRepetition), +} + +impl TokenTree { + pub fn len(&self) -> usize { + match *self { + TokenTree::Token(_, token::DocComment(name)) => { + match doc_comment_style(&name.as_str()) { + AttrStyle::Outer => 2, + AttrStyle::Inner => 3 + } + } + TokenTree::Token(_, token::SpecialVarNt(..)) => 2, + TokenTree::Token(_, token::MatchNt(..)) => 3, + TokenTree::Delimited(_, ref delimed) => { + delimed.tts.len() + 2 + } + TokenTree::Sequence(_, ref seq) => { + seq.tts.len() + } + TokenTree::Token(..) => 0 + } + } + + pub fn get_tt(&self, index: usize) -> TokenTree { + match (self, index) { + (&TokenTree::Token(sp, token::DocComment(_)), 0) => { + TokenTree::Token(sp, token::Pound) + } + (&TokenTree::Token(sp, token::DocComment(name)), 1) + if doc_comment_style(&name.as_str()) == AttrStyle::Inner => { + TokenTree::Token(sp, token::Not) + } + (&TokenTree::Token(sp, token::DocComment(name)), _) => { + let stripped = strip_doc_comment_decoration(&name.as_str()); + + // Searches for the occurrences of `"#*` and returns the minimum number of `#`s + // required to wrap the text. + let num_of_hashes = stripped.chars().scan(0, |cnt, x| { + *cnt = if x == '"' { + 1 + } else if *cnt != 0 && x == '#' { + *cnt + 1 + } else { + 0 + }; + Some(*cnt) + }).max().unwrap_or(0); + + TokenTree::Delimited(sp, Delimited { + delim: token::Bracket, + open_span: sp, + tts: vec![TokenTree::Token(sp, token::Ident(token::str_to_ident("doc"))), + TokenTree::Token(sp, token::Eq), + TokenTree::Token(sp, token::Literal( + token::StrRaw(token::intern(&stripped), num_of_hashes), None))], + close_span: sp, + }) + } + (&TokenTree::Delimited(_, ref delimed), _) => { + if index == 0 { + return delimed.open_tt(); + } + if index == delimed.tts.len() + 1 { + return delimed.close_tt(); + } + delimed.tts[index - 1].clone() + } + (&TokenTree::Token(sp, token::SpecialVarNt(var)), _) => { + let v = [TokenTree::Token(sp, token::Dollar), + TokenTree::Token(sp, token::Ident(token::str_to_ident(var.as_str())))]; + v[index].clone() + } + (&TokenTree::Token(sp, token::MatchNt(name, kind)), _) => { + let v = [TokenTree::Token(sp, token::SubstNt(name)), + TokenTree::Token(sp, token::Colon), + TokenTree::Token(sp, token::Ident(kind))]; + v[index].clone() + } + (&TokenTree::Sequence(_, ref seq), _) => { + seq.tts[index].clone() + } + _ => panic!("Cannot expand a token tree") + } + } + + /// Returns the `Span` corresponding to this token tree. + pub fn get_span(&self) -> Span { + match *self { + TokenTree::Token(span, _) => span, + TokenTree::Delimited(span, _) => span, + TokenTree::Sequence(span, _) => span, + } + } + + /// Use this token tree as a matcher to parse given tts. + pub fn parse(cx: &base::ExtCtxt, mtch: &[TokenTree], tts: &[TokenTree]) + -> macro_parser::NamedParseResult { + // `None` is because we're not interpolating + let arg_rdr = lexer::new_tt_reader_with_doc_flag(&cx.parse_sess().span_diagnostic, + None, + None, + tts.iter().cloned().collect(), + true); + macro_parser::parse(cx.parse_sess(), cx.cfg(), arg_rdr, mtch) + } +} + diff --git a/syntex_syntax/src/util/node_count.rs b/syntex_syntax/src/util/node_count.rs index 919dd84b..14244bbd 100644 --- a/syntex_syntax/src/util/node_count.rs +++ b/syntex_syntax/src/util/node_count.rs @@ -12,7 +12,7 @@ use visit::*; use ast::*; -use codemap::Span; +use syntax_pos::Span; pub struct NodeCounter { pub count: usize, @@ -26,133 +26,129 @@ impl NodeCounter { } } -impl<'v> Visitor<'v> for NodeCounter { +impl Visitor for NodeCounter { fn visit_ident(&mut self, span: Span, ident: Ident) { self.count += 1; walk_ident(self, span, ident); } - fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { + fn visit_mod(&mut self, m: &Mod, _s: Span, _n: NodeId) { self.count += 1; walk_mod(self, m) } - fn visit_foreign_item(&mut self, i: &'v ForeignItem) { + fn visit_foreign_item(&mut self, i: &ForeignItem) { self.count += 1; walk_foreign_item(self, i) } - fn visit_item(&mut self, i: &'v Item) { + fn visit_item(&mut self, i: &Item) { self.count += 1; walk_item(self, i) } - fn visit_local(&mut self, l: &'v Local) { + fn visit_local(&mut self, l: &Local) { self.count += 1; walk_local(self, l) } - fn visit_block(&mut self, b: &'v Block) { + fn visit_block(&mut self, b: &Block) { self.count += 1; walk_block(self, b) } - fn visit_stmt(&mut self, s: &'v Stmt) { + fn visit_stmt(&mut self, s: &Stmt) { self.count += 1; walk_stmt(self, s) } - fn visit_arm(&mut self, a: &'v Arm) { + fn visit_arm(&mut self, a: &Arm) { self.count += 1; walk_arm(self, a) } - fn visit_pat(&mut self, p: &'v Pat) { + fn visit_pat(&mut self, p: &Pat) { self.count += 1; walk_pat(self, p) } - fn visit_decl(&mut self, d: &'v Decl) { - self.count += 1; - walk_decl(self, d) - } - fn visit_expr(&mut self, ex: &'v Expr) { + fn visit_expr(&mut self, ex: &Expr) { self.count += 1; walk_expr(self, ex) } - fn visit_ty(&mut self, t: &'v Ty) { + fn visit_ty(&mut self, t: &Ty) { self.count += 1; walk_ty(self, t) } - fn visit_generics(&mut self, g: &'v Generics) { + fn visit_generics(&mut self, g: &Generics) { self.count += 1; walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) { + fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId) { self.count += 1; walk_fn(self, fk, fd, b, s) } - fn visit_trait_item(&mut self, ti: &'v TraitItem) { + fn visit_trait_item(&mut self, ti: &TraitItem) { self.count += 1; walk_trait_item(self, ti) } - fn visit_impl_item(&mut self, ii: &'v ImplItem) { + fn visit_impl_item(&mut self, ii: &ImplItem) { self.count += 1; walk_impl_item(self, ii) } - fn visit_trait_ref(&mut self, t: &'v TraitRef) { + fn visit_trait_ref(&mut self, t: &TraitRef) { self.count += 1; walk_trait_ref(self, t) } - fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) { + fn visit_ty_param_bound(&mut self, bounds: &TyParamBound) { self.count += 1; walk_ty_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) { self.count += 1; walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &'v VariantData, _: Ident, - _: &'v Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &VariantData, _: Ident, + _: &Generics, _: NodeId, _: Span) { self.count += 1; walk_struct_def(self, s) } - fn visit_struct_field(&mut self, s: &'v StructField) { + fn visit_struct_field(&mut self, s: &StructField) { self.count += 1; walk_struct_field(self, s) } - fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, - generics: &'v Generics, item_id: NodeId, _: Span) { + fn visit_enum_def(&mut self, enum_definition: &EnumDef, + generics: &Generics, item_id: NodeId, _: Span) { self.count += 1; walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) { self.count += 1; walk_variant(self, v, g, item_id) } - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + fn visit_lifetime(&mut self, lifetime: &Lifetime) { self.count += 1; walk_lifetime(self, lifetime) } - fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { + fn visit_lifetime_def(&mut self, lifetime: &LifetimeDef) { self.count += 1; walk_lifetime_def(self, lifetime) } - fn visit_mac(&mut self, _mac: &'v Mac) { + fn visit_mac(&mut self, _mac: &Mac) { self.count += 1; walk_mac(self, _mac) } - fn visit_path(&mut self, path: &'v Path, _id: NodeId) { + fn visit_path(&mut self, path: &Path, _id: NodeId) { self.count += 1; walk_path(self, path) } - fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) { + fn visit_path_list_item(&mut self, prefix: &Path, item: &PathListItem) { self.count += 1; walk_path_list_item(self, prefix, item) } - fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) { + fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &PathParameters) { self.count += 1; walk_path_parameters(self, path_span, path_parameters) } - fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) { + fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) { self.count += 1; walk_assoc_type_binding(self, type_binding) } - fn visit_attribute(&mut self, _attr: &'v Attribute) { + fn visit_attribute(&mut self, _attr: &Attribute) { self.count += 1; } - fn visit_macro_def(&mut self, macro_def: &'v MacroDef) { + fn visit_macro_def(&mut self, macro_def: &MacroDef) { self.count += 1; walk_macro_def(self, macro_def) } diff --git a/syntex_syntax/src/util/parser_testing.rs b/syntex_syntax/src/util/parser_testing.rs index 06264196..f59428bf 100644 --- a/syntex_syntax/src/util/parser_testing.rs +++ b/syntex_syntax/src/util/parser_testing.rs @@ -14,10 +14,11 @@ use parse::{lexer, new_parser_from_source_str}; use parse::parser::Parser; use parse::token; use ptr::P; +use tokenstream; use std::iter::Peekable; /// Map a string to tts, using a made-up filename: -pub fn string_to_tts(source_str: String) -> Vec { +pub fn string_to_tts(source_str: String) -> Vec { let ps = ParseSess::new(); filemap_to_tts(&ps, ps.codemap().new_filemap("bogofile".to_string(), None, source_str)) } diff --git a/syntex_syntax/src/util/thin_vec.rs b/syntex_syntax/src/util/thin_vec.rs new file mode 100644 index 00000000..546686b4 --- /dev/null +++ b/syntex_syntax/src/util/thin_vec.rs @@ -0,0 +1,59 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// A vector type optimized for cases where this size is usually 0 (c.f. `SmallVector`). +/// The `Option>` wrapping allows us to represent a zero sized vector with `None`, +/// which uses only a single (null) pointer. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ThinVec(Option>>); + +impl ThinVec { + pub fn new() -> Self { + ThinVec(None) + } +} + +impl From> for ThinVec { + fn from(vec: Vec) -> Self { + if vec.is_empty() { + ThinVec(None) + } else { + ThinVec(Some(Box::new(vec))) + } + } +} + +impl Into> for ThinVec { + fn into(self) -> Vec { + match self { + ThinVec(None) => Vec::new(), + ThinVec(Some(vec)) => *vec, + } + } +} + +impl ::std::ops::Deref for ThinVec { + type Target = [T]; + fn deref(&self) -> &[T] { + match *self { + ThinVec(None) => &[], + ThinVec(Some(ref vec)) => vec, + } + } +} + +impl Extend for ThinVec { + fn extend>(&mut self, iter: I) { + match *self { + ThinVec(Some(ref mut vec)) => vec.extend(iter), + ThinVec(None) => *self = iter.into_iter().collect::>().into(), + } + } +} diff --git a/syntex_syntax/src/visit.rs b/syntex_syntax/src/visit.rs index 07a63177..1fc4e54d 100644 --- a/syntex_syntax/src/visit.rs +++ b/syntex_syntax/src/visit.rs @@ -25,8 +25,8 @@ use abi::Abi; use ast::*; -use attr::ThinAttributesExt; -use codemap::{Span, Spanned}; +use syntax_pos::Span; +use codemap::Spanned; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { @@ -49,57 +49,56 @@ pub enum FnKind<'a> { /// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) -pub trait Visitor<'v> : Sized { +pub trait Visitor: Sized { fn visit_name(&mut self, _span: Span, _name: Name) { // Nothing to do. } fn visit_ident(&mut self, span: Span, ident: Ident) { walk_ident(self, span, ident); } - fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } - fn visit_foreign_item(&mut self, i: &'v ForeignItem) { walk_foreign_item(self, i) } - fn visit_item(&mut self, i: &'v Item) { walk_item(self, i) } - fn visit_local(&mut self, l: &'v Local) { walk_local(self, l) } - fn visit_block(&mut self, b: &'v Block) { walk_block(self, b) } - fn visit_stmt(&mut self, s: &'v Stmt) { walk_stmt(self, s) } - fn visit_arm(&mut self, a: &'v Arm) { walk_arm(self, a) } - fn visit_pat(&mut self, p: &'v Pat) { walk_pat(self, p) } - fn visit_decl(&mut self, d: &'v Decl) { walk_decl(self, d) } - fn visit_expr(&mut self, ex: &'v Expr) { walk_expr(self, ex) } - fn visit_expr_post(&mut self, _ex: &'v Expr) { } - fn visit_ty(&mut self, t: &'v Ty) { walk_ty(self, t) } - fn visit_generics(&mut self, g: &'v Generics) { walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) { + fn visit_mod(&mut self, m: &Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } + fn visit_foreign_item(&mut self, i: &ForeignItem) { walk_foreign_item(self, i) } + fn visit_item(&mut self, i: &Item) { walk_item(self, i) } + fn visit_local(&mut self, l: &Local) { walk_local(self, l) } + fn visit_block(&mut self, b: &Block) { walk_block(self, b) } + fn visit_stmt(&mut self, s: &Stmt) { walk_stmt(self, s) } + fn visit_arm(&mut self, a: &Arm) { walk_arm(self, a) } + fn visit_pat(&mut self, p: &Pat) { walk_pat(self, p) } + fn visit_expr(&mut self, ex: &Expr) { walk_expr(self, ex) } + fn visit_expr_post(&mut self, _ex: &Expr) { } + fn visit_ty(&mut self, t: &Ty) { walk_ty(self, t) } + fn visit_generics(&mut self, g: &Generics) { walk_generics(self, g) } + fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId) { walk_fn(self, fk, fd, b, s) } - fn visit_trait_item(&mut self, ti: &'v TraitItem) { walk_trait_item(self, ti) } - fn visit_impl_item(&mut self, ii: &'v ImplItem) { walk_impl_item(self, ii) } - fn visit_trait_ref(&mut self, t: &'v TraitRef) { walk_trait_ref(self, t) } - fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) { + fn visit_trait_item(&mut self, ti: &TraitItem) { walk_trait_item(self, ti) } + fn visit_impl_item(&mut self, ii: &ImplItem) { walk_impl_item(self, ii) } + fn visit_trait_ref(&mut self, t: &TraitRef) { walk_trait_ref(self, t) } + fn visit_ty_param_bound(&mut self, bounds: &TyParamBound) { walk_ty_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &'v VariantData, _: Ident, - _: &'v Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &VariantData, _: Ident, + _: &Generics, _: NodeId, _: Span) { walk_struct_def(self, s) } - fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) } - fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, - generics: &'v Generics, item_id: NodeId, _: Span) { + fn visit_struct_field(&mut self, s: &StructField) { walk_struct_field(self, s) } + fn visit_enum_def(&mut self, enum_definition: &EnumDef, + generics: &Generics, item_id: NodeId, _: Span) { walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) { walk_variant(self, v, g, item_id) } - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + fn visit_lifetime(&mut self, lifetime: &Lifetime) { walk_lifetime(self, lifetime) } - fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { + fn visit_lifetime_def(&mut self, lifetime: &LifetimeDef) { walk_lifetime_def(self, lifetime) } - fn visit_mac(&mut self, _mac: &'v Mac) { + fn visit_mac(&mut self, _mac: &Mac) { panic!("visit_mac disabled by default"); // NB: see note about macros above. // if you really want a visitor that @@ -107,26 +106,26 @@ pub trait Visitor<'v> : Sized { // definition in your trait impl: // visit::walk_mac(self, _mac) } - fn visit_path(&mut self, path: &'v Path, _id: NodeId) { + fn visit_path(&mut self, path: &Path, _id: NodeId) { walk_path(self, path) } - fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) { + fn visit_path_list_item(&mut self, prefix: &Path, item: &PathListItem) { walk_path_list_item(self, prefix, item) } - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) { + fn visit_path_segment(&mut self, path_span: Span, path_segment: &PathSegment) { walk_path_segment(self, path_span, path_segment) } - fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) { + fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &PathParameters) { walk_path_parameters(self, path_span, path_parameters) } - fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) { + fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) { walk_assoc_type_binding(self, type_binding) } - fn visit_attribute(&mut self, _attr: &'v Attribute) {} - fn visit_macro_def(&mut self, macro_def: &'v MacroDef) { + fn visit_attribute(&mut self, _attr: &Attribute) {} + fn visit_macro_def(&mut self, macro_def: &MacroDef) { walk_macro_def(self, macro_def) } - fn visit_vis(&mut self, vis: &'v Visibility) { + fn visit_vis(&mut self, vis: &Visibility) { walk_vis(self, vis) } } @@ -145,47 +144,46 @@ macro_rules! walk_list { } } -pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { +pub fn walk_opt_name(visitor: &mut V, span: Span, opt_name: Option) { if let Some(name) = opt_name { visitor.visit_name(span, name); } } -pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option) { +pub fn walk_opt_ident(visitor: &mut V, span: Span, opt_ident: Option) { if let Some(ident) = opt_ident { visitor.visit_ident(span, ident); } } -pub fn walk_opt_sp_ident<'v, V: Visitor<'v>>(visitor: &mut V, - opt_sp_ident: &Option>) { +pub fn walk_opt_sp_ident(visitor: &mut V, opt_sp_ident: &Option>) { if let Some(ref sp_ident) = *opt_sp_ident { visitor.visit_ident(sp_ident.span, sp_ident.node); } } -pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) { +pub fn walk_ident(visitor: &mut V, span: Span, ident: Ident) { visitor.visit_name(span, ident.name); } -pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { +pub fn walk_crate(visitor: &mut V, krate: &Crate) { visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); walk_list!(visitor, visit_attribute, &krate.attrs); walk_list!(visitor, visit_macro_def, &krate.exported_macros); } -pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) { +pub fn walk_macro_def(visitor: &mut V, macro_def: &MacroDef) { visitor.visit_ident(macro_def.span, macro_def.ident); walk_opt_ident(visitor, macro_def.span, macro_def.imported_from); walk_list!(visitor, visit_attribute, ¯o_def.attrs); } -pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { +pub fn walk_mod(visitor: &mut V, module: &Mod) { walk_list!(visitor, visit_item, &module.items); } -pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { - for attr in local.attrs.as_attr_slice() { +pub fn walk_local(visitor: &mut V, local: &Local) { + for attr in local.attrs.iter() { visitor.visit_attribute(attr); } visitor.visit_pat(&local.pat); @@ -193,33 +191,27 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { walk_list!(visitor, visit_expr, &local.init); } -pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { +pub fn walk_lifetime(visitor: &mut V, lifetime: &Lifetime) { visitor.visit_name(lifetime.span, lifetime.name); } -pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, - lifetime_def: &'v LifetimeDef) { +pub fn walk_lifetime_def(visitor: &mut V, lifetime_def: &LifetimeDef) { visitor.visit_lifetime(&lifetime_def.lifetime); walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); } -pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, - trait_ref: &'v PolyTraitRef, - _modifier: &'v TraitBoundModifier) - where V: Visitor<'v> +pub fn walk_poly_trait_ref(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier) + where V: Visitor, { walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); visitor.visit_trait_ref(&trait_ref.trait_ref); } -pub fn walk_trait_ref<'v,V>(visitor: &mut V, - trait_ref: &'v TraitRef) - where V: Visitor<'v> -{ +pub fn walk_trait_ref(visitor: &mut V, trait_ref: &TraitRef) { visitor.visit_path(&trait_ref.path, trait_ref.ref_id) } -pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { +pub fn walk_item(visitor: &mut V, item: &Item) { visitor.visit_vis(&item.vis); visitor.visit_ident(item.span, item.ident); match item.node { @@ -298,17 +290,16 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { walk_list!(visitor, visit_attribute, &item.attrs); } -pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, - enum_definition: &'v EnumDef, - generics: &'v Generics, - item_id: NodeId) { +pub fn walk_enum_def(visitor: &mut V, + enum_definition: &EnumDef, + generics: &Generics, + item_id: NodeId) { walk_list!(visitor, visit_variant, &enum_definition.variants, generics, item_id); } -pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, - variant: &'v Variant, - generics: &'v Generics, - item_id: NodeId) { +pub fn walk_variant(visitor: &mut V, variant: &Variant, generics: &Generics, item_id: NodeId) + where V: Visitor, +{ visitor.visit_ident(variant.span, variant.node.name); visitor.visit_variant_data(&variant.node.data, variant.node.name, generics, item_id, variant.span); @@ -316,7 +307,7 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, walk_list!(visitor, visit_attribute, &variant.node.attrs); } -pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { +pub fn walk_ty(visitor: &mut V, typ: &Ty) { match typ.node { TyKind::Vec(ref ty) | TyKind::Paren(ref ty) => { visitor.visit_ty(ty) @@ -362,28 +353,25 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { } } -pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { +pub fn walk_path(visitor: &mut V, path: &Path) { for segment in &path.segments { visitor.visit_path_segment(path.span, segment); } } -pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, _prefix: &'v Path, - item: &'v PathListItem) { +pub fn walk_path_list_item(visitor: &mut V, _prefix: &Path, item: &PathListItem) { walk_opt_ident(visitor, item.span, item.node.name()); walk_opt_ident(visitor, item.span, item.node.rename()); } -pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, - path_span: Span, - segment: &'v PathSegment) { +pub fn walk_path_segment(visitor: &mut V, path_span: Span, segment: &PathSegment) { visitor.visit_ident(path_span, segment.identifier); visitor.visit_path_parameters(path_span, &segment.parameters); } -pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, - _path_span: Span, - path_parameters: &'v PathParameters) { +pub fn walk_path_parameters(visitor: &mut V, _path_span: Span, path_parameters: &PathParameters) + where V: Visitor, +{ match *path_parameters { PathParameters::AngleBracketed(ref data) => { walk_list!(visitor, visit_ty, &data.types); @@ -397,23 +385,21 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, } } -pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, - type_binding: &'v TypeBinding) { +pub fn walk_assoc_type_binding(visitor: &mut V, type_binding: &TypeBinding) { visitor.visit_ident(type_binding.span, type_binding.ident); visitor.visit_ty(&type_binding.ty); } -pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { +pub fn walk_pat(visitor: &mut V, pattern: &Pat) { match pattern.node { PatKind::TupleStruct(ref path, ref children, _) => { visitor.visit_path(path, pattern.id); walk_list!(visitor, visit_pat, children); } - PatKind::Path(ref path) => { - visitor.visit_path(path, pattern.id); - } - PatKind::QPath(ref qself, ref path) => { - visitor.visit_ty(&qself.ty); + PatKind::Path(ref opt_qself, ref path) => { + if let Some(ref qself) = *opt_qself { + visitor.visit_ty(&qself.ty); + } visitor.visit_path(path, pattern.id) } PatKind::Struct(ref path, ref fields, _) => { @@ -449,8 +435,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { } } -pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, - foreign_item: &'v ForeignItem) { +pub fn walk_foreign_item(visitor: &mut V, foreign_item: &ForeignItem) { visitor.visit_vis(&foreign_item.vis); visitor.visit_ident(foreign_item.span, foreign_item.ident); @@ -465,8 +450,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, walk_list!(visitor, visit_attribute, &foreign_item.attrs); } -pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, - bound: &'v TyParamBound) { +pub fn walk_ty_param_bound(visitor: &mut V, bound: &TyParamBound) { match *bound { TraitTyParamBound(ref typ, ref modifier) => { visitor.visit_poly_trait_ref(typ, modifier); @@ -477,7 +461,7 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, } } -pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { +pub fn walk_generics(visitor: &mut V, generics: &Generics) { for param in &generics.ty_params { visitor.visit_ident(param.span, param.ident); walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); @@ -511,13 +495,13 @@ pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics } } -pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy) { +pub fn walk_fn_ret_ty(visitor: &mut V, ret_ty: &FunctionRetTy) { if let FunctionRetTy::Ty(ref output_ty) = *ret_ty { visitor.visit_ty(output_ty) } } -pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { +pub fn walk_fn_decl(visitor: &mut V, function_declaration: &FnDecl) { for argument in &function_declaration.inputs { visitor.visit_pat(&argument.pat); visitor.visit_ty(&argument.ty) @@ -525,8 +509,7 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: & walk_fn_ret_ty(visitor, &function_declaration.output) } -pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, - function_kind: FnKind<'v>) { +pub fn walk_fn_kind(visitor: &mut V, function_kind: FnKind) { match function_kind { FnKind::ItemFn(_, generics, _, _, _, _) => { visitor.visit_generics(generics); @@ -538,17 +521,15 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, } } -pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, - function_kind: FnKind<'v>, - function_declaration: &'v FnDecl, - function_body: &'v Block, - _span: Span) { - walk_fn_decl(visitor, function_declaration); - walk_fn_kind(visitor, function_kind); - visitor.visit_block(function_body) +pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, body: &Block, _span: Span) + where V: Visitor, +{ + walk_fn_decl(visitor, declaration); + walk_fn_kind(visitor, kind); + visitor.visit_block(body) } -pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) { +pub fn walk_trait_item(visitor: &mut V, trait_item: &TraitItem) { visitor.visit_ident(trait_item.span, trait_item.ident); walk_list!(visitor, visit_attribute, &trait_item.attrs); match trait_item.node { @@ -568,10 +549,13 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_ty, default); } + TraitItemKind::Macro(ref mac) => { + visitor.visit_mac(mac); + } } } -pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) { +pub fn walk_impl_item(visitor: &mut V, impl_item: &ImplItem) { visitor.visit_vis(&impl_item.vis); visitor.visit_ident(impl_item.span, impl_item.ident); walk_list!(visitor, visit_attribute, &impl_item.attrs); @@ -593,52 +577,44 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } } -pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, - struct_definition: &'v VariantData) { +pub fn walk_struct_def(visitor: &mut V, struct_definition: &VariantData) { walk_list!(visitor, visit_struct_field, struct_definition.fields()); } -pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, - struct_field: &'v StructField) { +pub fn walk_struct_field(visitor: &mut V, struct_field: &StructField) { visitor.visit_vis(&struct_field.vis); walk_opt_ident(visitor, struct_field.span, struct_field.ident); visitor.visit_ty(&struct_field.ty); walk_list!(visitor, visit_attribute, &struct_field.attrs); } -pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { +pub fn walk_block(visitor: &mut V, block: &Block) { walk_list!(visitor, visit_stmt, &block.stmts); - walk_list!(visitor, visit_expr, &block.expr); } -pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { +pub fn walk_stmt(visitor: &mut V, statement: &Stmt) { match statement.node { - StmtKind::Decl(ref declaration, _) => visitor.visit_decl(declaration), - StmtKind::Expr(ref expression, _) | StmtKind::Semi(ref expression, _) => { + StmtKind::Local(ref local) => visitor.visit_local(local), + StmtKind::Item(ref item) => visitor.visit_item(item), + StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { visitor.visit_expr(expression) } - StmtKind::Mac(ref mac, _, ref attrs) => { + StmtKind::Mac(ref mac) => { + let (ref mac, _, ref attrs) = **mac; visitor.visit_mac(mac); - for attr in attrs.as_attr_slice() { + for attr in attrs.iter() { visitor.visit_attribute(attr); } } } } -pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) { - match declaration.node { - DeclKind::Local(ref local) => visitor.visit_local(local), - DeclKind::Item(ref item) => visitor.visit_item(item), - } -} - -pub fn walk_mac<'v, V: Visitor<'v>>(_: &mut V, _: &'v Mac) { +pub fn walk_mac(_: &mut V, _: &Mac) { // Empty! } -pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { - for attr in expression.attrs.as_attr_slice() { +pub fn walk_expr(visitor: &mut V, expression: &Expr) { + for attr in expression.attrs.iter() { visitor.visit_attribute(attr); } match expression.node { @@ -761,7 +737,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } visitor.visit_path(path, expression.id) } - ExprKind::Break(ref opt_sp_ident) | ExprKind::Again(ref opt_sp_ident) => { + ExprKind::Break(ref opt_sp_ident) | ExprKind::Continue(ref opt_sp_ident) => { walk_opt_sp_ident(visitor, opt_sp_ident); } ExprKind::Ret(ref optional_expression) => { @@ -787,14 +763,14 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr_post(expression) } -pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { +pub fn walk_arm(visitor: &mut V, arm: &Arm) { walk_list!(visitor, visit_pat, &arm.pats); walk_list!(visitor, visit_expr, &arm.guard); visitor.visit_expr(&arm.body); walk_list!(visitor, visit_attribute, &arm.attrs); } -pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) { +pub fn walk_vis(visitor: &mut V, vis: &Visibility) { if let Visibility::Restricted { ref path, id } = *vis { visitor.visit_path(path, id); }