Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add path suffix lookup #16326

Merged
merged 5 commits into from
Aug 9, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
349 changes: 297 additions & 52 deletions src/librustc/driver/driver.rs

Large diffs are not rendered by default.

45 changes: 22 additions & 23 deletions src/librustc/driver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ fn run_compiler(args: &[String]) {
parse_pretty(&sess, a.as_slice())
});
match pretty {
Some::<PpMode>(ppm) => {
driver::pretty_print_input(sess, cfg, &input, ppm, ofile);
Some((ppm, opt_uii)) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woah, woah. Type ascription in a pattern!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... #16353

driver::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile);
return;
}
None::<PpMode> => {/* continue */ }
None => {/* continue */ }
}

let r = matches.opt_strs("Z");
Expand Down Expand Up @@ -340,42 +340,41 @@ fn print_crate_info(sess: &Session,
}
}

pub enum PpMode {
#[deriving(PartialEq, Show)]
pub enum PpSourceMode {
PpmNormal,
PpmExpanded,
PpmTyped,
PpmIdentified,
PpmExpandedIdentified,
PpmFlowGraph(ast::NodeId),
}

pub fn parse_pretty(sess: &Session, name: &str) -> PpMode {
#[deriving(PartialEq, Show)]
pub enum PpMode {
PpmSource(PpSourceMode),
PpmFlowGraph,
}

fn parse_pretty(sess: &Session, name: &str) -> (PpMode, Option<driver::UserIdentifiedItem>) {
let mut split = name.splitn('=', 1);
let first = split.next().unwrap();
let opt_second = split.next();
match (opt_second, first) {
(None, "normal") => PpmNormal,
(None, "expanded") => PpmExpanded,
(None, "typed") => PpmTyped,
(None, "expanded,identified") => PpmExpandedIdentified,
(None, "identified") => PpmIdentified,
(arg, "flowgraph") => {
match arg.and_then(from_str) {
Some(id) => PpmFlowGraph(id),
None => {
sess.fatal(format!("`pretty flowgraph=<nodeid>` needs \
an integer <nodeid>; got {}",
arg.unwrap_or("nothing")).as_slice())
}
}
}
let first = match first {
"normal" => PpmSource(PpmNormal),
"expanded" => PpmSource(PpmExpanded),
"typed" => PpmSource(PpmTyped),
"expanded,identified" => PpmSource(PpmExpandedIdentified),
"identified" => PpmSource(PpmIdentified),
"flowgraph" => PpmFlowGraph,
_ => {
sess.fatal(format!(
"argument to `pretty` must be one of `normal`, \
`expanded`, `flowgraph=<nodeid>`, `typed`, `identified`, \
or `expanded,identified`; got {}", name).as_slice());
}
}
};
let opt_second = opt_second.and_then::<driver::UserIdentifiedItem>(from_str);
(first, opt_second)
}

fn parse_crate_attrs(sess: &Session, input: &Input) ->
Expand Down
162 changes: 161 additions & 1 deletion src/libsyntax/ast_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use abi;
use ast::*;
use ast_util;
use codemap::Span;
use codemap::{Span, Spanned};
use fold::Folder;
use fold;
use parse::token;
Expand All @@ -21,6 +21,7 @@ use util::small_vector::SmallVector;
use std::cell::RefCell;
use std::fmt;
use std::gc::{Gc, GC};
use std::io::IoResult;
use std::iter;
use std::slice;

Expand Down Expand Up @@ -203,6 +204,10 @@ pub struct Map {
}

impl Map {
fn entry_count(&self) -> uint {
self.map.borrow().len()
}

fn find_entry(&self, id: NodeId) -> Option<MapEntry> {
let map = self.map.borrow();
if map.len() > id as uint {
Expand Down Expand Up @@ -405,6 +410,20 @@ impl Map {
f(attrs)
}

/// Returns an iterator that yields the node id's with paths that
/// match `parts`. (Requires `parts` is non-empty.)
///
/// For example, if given `parts` equal to `["bar", "quux"]`, then
/// the iterator will produce node id's for items with paths
/// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and
/// any other such items it can find in the map.
pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S]) -> NodesMatchingSuffix<'a,S> {
NodesMatchingSuffix { map: self,
item_name: parts.last().unwrap(),
where: parts.slice_to(parts.len() - 1),
idx: 0 }
}

pub fn opt_span(&self, id: NodeId) -> Option<Span> {
let sp = match self.find(id) {
Some(NodeItem(item)) => item.span,
Expand Down Expand Up @@ -438,6 +457,119 @@ impl Map {
}
}

pub struct NodesMatchingSuffix<'a, S> {
map: &'a Map,
item_name: &'a S,
where: &'a [S],
idx: NodeId,
}

impl<'a,S:Str> NodesMatchingSuffix<'a,S> {
/// Returns true only if some suffix of the module path for parent
/// matches `self.where`.
///
/// In other words: let `[x_0,x_1,...,x_k]` be `self.where`;
/// returns true if parent's path ends with the suffix
/// `x_0::x_1::...::x_k`.
fn suffix_matches(&self, parent: NodeId) -> bool {
let mut cursor = parent;
for part in self.where.iter().rev() {
let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) {
None => return false,
Some((node_id, name)) => (node_id, name),
};
if part.as_slice() != mod_name.as_str() {
return false;
}
cursor = self.map.get_parent(mod_id);
}
return true;

// Finds the first mod in parent chain for `id`, along with
// that mod's name.
//
// If `id` itself is a mod named `m` with parent `p`, then
// returns `Some(id, m, p)`. If `id` has no mod in its parent
// chain, then returns `None`.
fn find_first_mod_parent<'a>(map: &'a Map, mut id: NodeId) -> Option<(NodeId, Name)> {
loop {
match map.find(id) {
None => return None,
Some(NodeItem(item)) if item_is_mod(&*item) =>
return Some((id, item.ident.name)),
_ => {}
}
let parent = map.get_parent(id);
if parent == id { return None }
id = parent;
}

fn item_is_mod(item: &Item) -> bool {
match item.node {
ItemMod(_) => true,
_ => false,
}
}
}
}

// We are looking at some node `n` with a given name and parent
// id; do their names match what I am seeking?
fn matches_names(&self, parent_of_n: NodeId, name: Name) -> bool {
name.as_str() == self.item_name.as_slice() &&
self.suffix_matches(parent_of_n)
}
}

impl<'a,S:Str> Iterator<NodeId> for NodesMatchingSuffix<'a,S> {
fn next(&mut self) -> Option<NodeId> {
loop {
let idx = self.idx;
if idx as uint >= self.map.entry_count() {
return None;
}
self.idx += 1;
let (p, name) = match self.map.find_entry(idx) {
Some(EntryItem(p, n)) => (p, n.name()),
Some(EntryForeignItem(p, n)) => (p, n.name()),
Some(EntryTraitMethod(p, n)) => (p, n.name()),
Some(EntryMethod(p, n)) => (p, n.name()),
Some(EntryVariant(p, n)) => (p, n.name()),
_ => continue,
};
if self.matches_names(p, name) {
return Some(idx)
}
}
}
}

trait Named {
fn name(&self) -> Name;
}

impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() } }

impl Named for Item { fn name(&self) -> Name { self.ident.name } }
impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } }
impl Named for Variant_ { fn name(&self) -> Name { self.name.name } }
impl Named for TraitMethod {
fn name(&self) -> Name {
match *self {
Required(ref tm) => tm.ident.name,
Provided(m) => m.name(),
}
}
}
impl Named for Method {
fn name(&self) -> Name {
match self.node {
MethDecl(i, _, _, _, _, _, _, _) => i.name,
MethMac(_) => fail!("encountered unexpanded method macro."),
}
}
}

pub trait FoldOps {
fn new_id(&self, id: NodeId) -> NodeId {
id
Expand Down Expand Up @@ -688,6 +820,34 @@ pub fn map_decoded_item<F: FoldOps>(map: &Map,
ii
}

pub trait NodePrinter {
fn print_node(&mut self, node: &Node) -> IoResult<()>;
}

impl<'a> NodePrinter for pprust::State<'a> {
fn print_node(&mut self, node: &Node) -> IoResult<()> {
match *node {
NodeItem(a) => self.print_item(&*a),
NodeForeignItem(a) => self.print_foreign_item(&*a),
NodeTraitMethod(a) => self.print_trait_method(&*a),
NodeMethod(a) => self.print_method(&*a),
NodeVariant(a) => self.print_variant(&*a),
NodeExpr(a) => self.print_expr(&*a),
NodeStmt(a) => self.print_stmt(&*a),
NodePat(a) => self.print_pat(&*a),
NodeBlock(a) => self.print_block(&*a),
NodeLifetime(a) => self.print_lifetime(&*a),

// these cases do not carry enough information in the
// ast_map to reconstruct their full structure for pretty
// printing.
NodeLocal(_) => fail!("cannot print isolated Local"),
NodeArg(_) => fail!("cannot print isolated Arg"),
NodeStructCtor(_) => fail!("cannot print isolated StructCtor"),
}
}
}

fn node_id_to_string(map: &Map, id: NodeId) -> String {
match map.find(id) {
Some(NodeItem(item)) => {
Expand Down
75 changes: 51 additions & 24 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,35 +97,62 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
out: Box<io::Writer>,
ann: &'a PpAnn,
is_expanded: bool) -> IoResult<()> {
let (cmnts, lits) = comments::gather_comments_and_literals(
span_diagnostic,
filename,
input
);
let mut s = State {
s: pp::mk_printer(out, default_columns),
cm: Some(cm),
comments: Some(cmnts),
// If the code is post expansion, don't use the table of
// literals, since it doesn't correspond with the literals
// in the AST anymore.
literals: if is_expanded {
None
} else {
Some(lits)
},
cur_cmnt_and_lit: CurrentCommentAndLiteral {
cur_cmnt: 0,
cur_lit: 0
},
boxes: Vec::new(),
ann: ann
};
let mut s = State::new_from_input(cm,
span_diagnostic,
filename,
input,
out,
ann,
is_expanded);
try!(s.print_mod(&krate.module, krate.attrs.as_slice()));
try!(s.print_remaining_comments());
eof(&mut s.s)
}

impl<'a> State<'a> {
pub fn new_from_input(cm: &'a CodeMap,
span_diagnostic: &diagnostic::SpanHandler,
filename: String,
input: &mut io::Reader,
out: Box<io::Writer>,
ann: &'a PpAnn,
is_expanded: bool) -> State<'a> {
let (cmnts, lits) = comments::gather_comments_and_literals(
span_diagnostic,
filename,
input);

State::new(
cm,
out,
ann,
Some(cmnts),
// If the code is post expansion, don't use the table of
// literals, since it doesn't correspond with the literals
// in the AST anymore.
if is_expanded { None } else { Some(lits) })
}

pub fn new(cm: &'a CodeMap,
out: Box<io::Writer>,
ann: &'a PpAnn,
comments: Option<Vec<comments::Comment>>,
literals: Option<Vec<comments::Literal>>) -> State<'a> {
State {
s: pp::mk_printer(out, default_columns),
cm: Some(cm),
comments: comments,
literals: literals,
cur_cmnt_and_lit: CurrentCommentAndLiteral {
cur_cmnt: 0,
cur_lit: 0
},
boxes: Vec::new(),
ann: ann
}
}
}

pub fn to_string(f: |&mut State| -> IoResult<()>) -> String {
let mut s = rust_printer(box MemWriter::new());
f(&mut s).unwrap();
Expand Down
9 changes: 9 additions & 0 deletions src/test/run-make/pretty-print-path-suffix/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-include ../tools.mk

all:
$(RUSTC) -o $(TMPDIR)/foo.out --pretty normal=foo input.rs
$(RUSTC) -o $(TMPDIR)/nest_foo.out --pretty normal=nest::foo input.rs
$(RUSTC) -o $(TMPDIR)/foo_method.out --pretty normal=foo_method input.rs
diff -u $(TMPDIR)/foo.out foo.pp
diff -u $(TMPDIR)/nest_foo.out nest_foo.pp
diff -u $(TMPDIR)/foo_method.out foo_method.pp
15 changes: 15 additions & 0 deletions src/test/run-make/pretty-print-path-suffix/foo.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.


pub fn foo() -> i32 { 45 } /* foo */


pub fn foo() -> &'static str { "i am a foo." } /* nest::foo */
Loading