Remove dependence on rustc/rustc_driver, use syntex

Instead just parse manually with the `syntex_syntax` crate which is a clone of
libsyntax on crates.io which builds on stable Rust.
This commit is contained in:
Alex Crichton 2015-10-22 14:37:13 -07:00
parent 36abfe5dc2
commit 579fb34417
5 changed files with 57 additions and 122 deletions

24
Cargo.lock generated
View File

@ -8,6 +8,7 @@ dependencies = [
"regex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"strings 0.0.1 (git+https://github.com/nrc/strings.rs.git)",
"syntex_syntax 0.18.0 (git+https://github.com/serde-rs/syntex)",
"term 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -21,6 +22,11 @@ dependencies = [
"memchr 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "diff"
version = "0.1.7"
@ -93,6 +99,19 @@ dependencies = [
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syntex_syntax"
version = "0.18.0"
source = "git+https://github.com/serde-rs/syntex#176ca5d8add606fac8d503b10c89ddb82f02d92b"
dependencies = [
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "term"
version = "0.2.12"
@ -115,6 +134,11 @@ name = "unicode-segmentation"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.4"

View File

@ -16,6 +16,7 @@ regex = "0.1.41"
term = "0.2.11"
strings = { version = "0.0.1", git = "https://github.com/nrc/strings.rs.git" }
diff = { git = "https://github.com/utkarshkukreti/diff.rs.git" }
syntex_syntax = { git = "https://github.com/serde-rs/syntex" }
log = "0.3.2"
env_logger = "0.3.1"

View File

@ -15,10 +15,7 @@
#[macro_use]
extern crate log;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate syntax;
extern crate syntex_syntax as syntax;
extern crate rustc_serialize;
extern crate strings;
@ -28,22 +25,15 @@ extern crate regex;
extern crate diff;
extern crate term;
use rustc::session::Session;
use rustc::session::config as rustc_config;
use rustc::session::config::Input;
use rustc_driver::{driver, CompilerCalls, Compilation};
use syntax::ast;
use syntax::codemap::{CodeMap, Span};
use syntax::diagnostics;
use syntax::parse::{self, ParseSess};
use std::ops::{Add, Sub};
use std::path::PathBuf;
use std::path::Path;
use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
use std::rc::Rc;
use std::cell::RefCell;
use issues::{BadIssueSeeker, Issue};
use filemap::FileMap;
@ -380,65 +370,24 @@ pub fn fmt_lines(file_map: &mut FileMap, config: &Config) -> FormatReport {
report
}
struct RustFmtCalls {
config: Rc<Config>,
result: Rc<RefCell<Option<FileMap>>>,
}
pub fn format(file: &Path, config: &Config) -> FileMap {
let parse_session = ParseSess::new();
let krate = parse::parse_crate_from_file(file, Vec::new(), &parse_session);
let mut file_map = fmt_ast(&krate, parse_session.codemap(), config);
impl<'a> CompilerCalls<'a> for RustFmtCalls {
fn no_input(&mut self,
_: &getopts::Matches,
_: &rustc_config::Options,
_: &Option<PathBuf>,
_: &Option<PathBuf>,
_: &diagnostics::registry::Registry)
-> Option<(Input, Option<PathBuf>)> {
panic!("No input supplied to RustFmt");
}
// For some reason, the codemap does not include terminating
// newlines so we must add one on for each file. This is sad.
filemap::append_newlines(&mut file_map);
fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> {
let result = self.result.clone();
let config = self.config.clone();
let mut control = driver::CompileController::basic();
control.after_parse.stop = Compilation::Stop;
control.after_parse.callback = Box::new(move |state| {
let krate = state.krate.unwrap();
let codemap = state.session.codemap();
let mut file_map = fmt_ast(krate, codemap, &*config);
// For some reason, the codemap does not include terminating
// newlines so we must add one on for each file. This is sad.
filemap::append_newlines(&mut file_map);
*result.borrow_mut() = Some(file_map);
});
control
}
}
pub fn format(args: Vec<String>, config: &Config) -> FileMap {
let result = Rc::new(RefCell::new(None));
{
let config = Rc::new(config.clone());
let mut call_ctxt = RustFmtCalls {
config: config,
result: result.clone(),
};
rustc_driver::run_compiler(&args, &mut call_ctxt);
}
// Peel the union.
Rc::try_unwrap(result).ok().unwrap().into_inner().unwrap()
return file_map;
}
// args are the arguments passed on the command line, generally passed through
// to the compiler.
// write_mode determines what happens to the result of running rustfmt, see
// WriteMode.
pub fn run(args: Vec<String>, write_mode: WriteMode, config: &Config) {
let mut result = format(args, config);
pub fn run(file: &Path, write_mode: WriteMode, config: &Config) {
let mut result = format(file, config);
println!("{}", fmt_lines(&mut result, config));

View File

@ -19,15 +19,10 @@
// List-like invocations with parentheses will be formatted as function calls,
// and those with brackets will be formatted as array literals.
use std::thread;
use std::collections::hash_map::{HashMap, Entry};
use syntax::ast;
use syntax::parse::token::{Eof, Comma, Token};
use syntax::parse::{ParseSess, tts_to_parser};
use syntax::codemap::{mk_sp, BytePos};
use syntax::parse::token;
use syntax::util::interner::StrInterner;
use Indent;
use rewrite::RewriteContext;
@ -37,12 +32,6 @@ use utils::{wrap_str, span_after};
static FORCED_BRACKET_MACROS: &'static [&'static str] = &["vec!"];
// We need to pass `TokenTree`s to our expression parsing thread, but they are
// not `Send`. We wrap them in a `Send` container to force our will.
// FIXME: this is a pretty terrible hack. Any other solution would be preferred.
struct ForceSend<T>(pub T);
unsafe impl<T> Send for ForceSend<T> {}
// FIXME: use the enum from libsyntax?
#[derive(Clone, Copy)]
enum MacroStyle {
@ -84,38 +73,28 @@ pub fn rewrite_macro(mac: &ast::Mac,
};
}
let wrapped_tt_vec = ForceSend(mac.node.tts.clone());
let my_interner = ForceSend(clone_interner());
let parse_session = ParseSess::new();
let mut parser = tts_to_parser(&parse_session, mac.node.tts.clone(), Vec::new());
let mut expr_vec = Vec::new();
// Wrap expression parsing logic in a thread since the libsyntax parser
// panics on failure, which we do not want to propagate.
// The expression vector is wrapped in an Option inside a Result.
let expr_vec_result = thread::spawn(move || {
let parse_session = ParseSess::new();
let mut parser = tts_to_parser(&parse_session, wrapped_tt_vec.0, vec![]);
let mut expr_vec = vec![];
token::get_ident_interner().reset(my_interner.0);
loop {
expr_vec.push(match parser.parse_expr_nopanic() {
Ok(expr) => expr,
Err(..) => return None,
});
loop {
expr_vec.push(parser.parse_expr());
match parser.token {
Token::Eof => break,
Token::Comma => (),
_ => panic!("Macro not list-like, skiping..."),
}
let _ = parser.bump();
if parser.token == Token::Eof {
return None;
}
match parser.token {
Token::Eof => break,
Token::Comma => (),
_ => return None,
}
Some(ForceSend((expr_vec, clone_interner())))
});
let (expr_vec, interner) = try_opt!(try_opt!(expr_vec_result.join().ok())).0;
token::get_ident_interner().reset(interner);
let _ = parser.bump();
if parser.token == Token::Eof {
return None;
}
}
match style {
MacroStyle::Parens => {
@ -146,23 +125,6 @@ pub fn rewrite_macro(mac: &ast::Mac,
}
}
fn clone_interner() -> StrInterner {
let old = token::get_ident_interner();
let new = StrInterner::new();
let mut map = HashMap::new();
for name in (0..old.len()).map(|i| i as u32).map(ast::Name) {
match map.entry(old.get(name)) {
Entry::Occupied(e) => {
new.gensym_copy(*e.get());
}
Entry::Vacant(e) => {
e.insert(new.intern(&old.get(name)));
}
}
}
return new
}
fn macro_style(mac: &ast::Mac, context: &RewriteContext) -> MacroStyle {
let snippet = context.snippet(mac.span);
let paren_pos = snippet.find_uncommented("(").unwrap_or(usize::max_value());

View File

@ -135,7 +135,6 @@ fn print_mismatches(result: HashMap<String, Vec<Mismatch>>) {
pub fn idempotent_check(filename: String) -> Result<FormatReport, HashMap<String, Vec<Mismatch>>> {
let sig_comments = read_significant_comments(&filename);
let mut config = get_config(sig_comments.get("config").map(|x| &(*x)[..]));
let args = vec!["rustfmt".to_owned(), filename];
for (key, val) in &sig_comments {
if key != "target" && key != "config" {
@ -146,7 +145,7 @@ pub fn idempotent_check(filename: String) -> Result<FormatReport, HashMap<String
// Don't generate warnings for to-do items.
config.report_todo = ReportTactic::Never;
let mut file_map = format(args, &config);
let mut file_map = format(Path::new(&filename), &config);
let format_report = fmt_lines(&mut file_map, &config);
// Won't panic, as we're not doing any IO.