rustc: implement a pretty mode to print ident/name's ctxt & gensyms.

`--pretty expanded,hygiene` is helpful with debugging macro issues,
since two identifiers/names can be textually the same, but different
internally (resulting in weird "undefined variable" errors).
This commit is contained in:
Huon Wilson 2014-08-11 22:01:37 +10:00
parent ddc8cc92c9
commit 32e437161d
6 changed files with 116 additions and 3 deletions

View File

@ -42,6 +42,7 @@ pub enum PpSourceMode {
PpmTyped,
PpmIdentified,
PpmExpandedIdentified,
PpmExpandedHygiene,
}
#[deriving(PartialEq, Show)]
@ -59,6 +60,7 @@ pub fn parse_pretty(sess: &Session, name: &str) -> (PpMode, Option<UserIdentifie
"expanded" => PpmSource(PpmExpanded),
"typed" => PpmSource(PpmTyped),
"expanded,identified" => PpmSource(PpmExpandedIdentified),
"expanded,hygiene" => PpmSource(PpmExpandedHygiene),
"identified" => PpmSource(PpmIdentified),
"flowgraph" => PpmFlowGraph,
_ => {
@ -106,6 +108,10 @@ impl PpSourceMode {
let annotation = IdentifiedAnnotation { sess: sess, ast_map: ast_map };
f(&annotation, payload)
}
PpmExpandedHygiene => {
let annotation = HygieneAnnotation { sess: sess, ast_map: ast_map };
f(&annotation, payload)
}
PpmTyped => {
let ast_map = ast_map.expect("--pretty=typed missing ast_map");
let analysis = driver::phase_3_run_analysis_passes(sess, krate, ast_map, id);
@ -191,6 +197,8 @@ impl pprust::PpAnn for IdentifiedAnnotation {
s: &mut pprust::State,
node: pprust::AnnNode) -> io::IoResult<()> {
match node {
pprust::NodeIdent(_) | pprust::NodeName(_) => Ok(()),
pprust::NodeItem(item) => {
try!(pp::space(&mut s.s));
s.synth_comment(item.id.to_string())
@ -212,6 +220,46 @@ impl pprust::PpAnn for IdentifiedAnnotation {
}
}
struct HygieneAnnotation {
sess: Session,
ast_map: Option<ast_map::Map>,
}
impl PrinterSupport for HygieneAnnotation {
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self as &pprust::PpAnn }
}
impl SessionCarrier for HygieneAnnotation {
fn sess<'a>(&'a self) -> &'a Session { &self.sess }
}
impl AstMapCarrier for HygieneAnnotation {
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map> {
self.ast_map.as_ref()
}
}
impl pprust::PpAnn for HygieneAnnotation {
fn post(&self,
s: &mut pprust::State,
node: pprust::AnnNode) -> io::IoResult<()> {
match node {
pprust::NodeIdent(&ast::Ident { name: ast::Name(nm), ctxt }) => {
try!(pp::space(&mut s.s));
// FIXME #16420: this doesn't display the connections
// between syntax contexts
s.synth_comment(format!("{}#{}", nm, ctxt))
}
pprust::NodeName(&ast::Name(nm)) => {
try!(pp::space(&mut s.s));
s.synth_comment(nm.to_string())
}
_ => Ok(())
}
}
}
struct TypedAnnotation {
analysis: CrateAnalysis,
}
@ -364,6 +412,7 @@ fn needs_ast_map(ppm: &PpMode, opt_uii: &Option<UserIdentifiedItem>) -> bool {
PpmSource(PpmExpanded) |
PpmSource(PpmExpandedIdentified) |
PpmSource(PpmExpandedHygiene) |
PpmSource(PpmTyped) |
PpmFlowGraph => true
}
@ -376,6 +425,7 @@ fn needs_expansion(ppm: &PpMode) -> bool {
PpmSource(PpmExpanded) |
PpmSource(PpmExpandedIdentified) |
PpmSource(PpmExpandedHygiene) |
PpmSource(PpmTyped) |
PpmFlowGraph => true
}

View File

@ -111,6 +111,7 @@ impl<'a, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, O> {
ps: &mut pprust::State,
node: pprust::AnnNode) -> io::IoResult<()> {
let id = match node {
pprust::NodeIdent(_) | pprust::NodeName(_) => 0,
pprust::NodeExpr(expr) => expr.id,
pprust::NodeBlock(blk) => blk.id,
pprust::NodeItem(_) => 0,

View File

@ -33,6 +33,8 @@ use std::io;
use std::mem;
pub enum AnnNode<'a> {
NodeIdent(&'a ast::Ident),
NodeName(&'a ast::Name),
NodeBlock(&'a ast::Block),
NodeItem(&'a ast::Item),
NodeExpr(&'a ast::Expr),
@ -1725,14 +1727,16 @@ impl<'a> State<'a> {
pub fn print_ident(&mut self, ident: ast::Ident) -> IoResult<()> {
if self.encode_idents_with_hygiene {
let encoded = ident.encode_with_hygiene();
word(&mut self.s, encoded.as_slice())
try!(word(&mut self.s, encoded.as_slice()))
} else {
word(&mut self.s, token::get_ident(ident).get())
try!(word(&mut self.s, token::get_ident(ident).get()))
}
self.ann.post(self, NodeIdent(&ident))
}
pub fn print_name(&mut self, name: ast::Name) -> IoResult<()> {
word(&mut self.s, token::get_name(name).get())
try!(word(&mut self.s, token::get_name(name).get()));
self.ann.post(self, NodeName(&name))
}
pub fn print_for_decl(&mut self, loc: &ast::Local,

View File

@ -0,0 +1,20 @@
-include ../tools.mk
REPLACEMENT := s/[0-9][0-9]*\#[0-9][0-9]*/$(shell date)/g
all:
$(RUSTC) -o $(TMPDIR)/input.out --pretty expanded,hygiene input.rs
# the name/ctxt numbers are very internals-dependent and thus
# change relatively frequently, and testing for their exact values
# them will fail annoyingly, so we just check their positions
# (using a non-constant replacement like this will make it less
# likely the compiler matches whatever other dummy value we
# choose).
#
# (These need to be out-of-place because OSX/BSD & GNU sed
# differ.)
sed "$(REPLACEMENT)" input.pp.rs > $(TMPDIR)/input.pp.rs
sed "$(REPLACEMENT)" $(TMPDIR)/input.out > $(TMPDIR)/input.out.replaced
diff -u $(TMPDIR)/input.out.replaced $(TMPDIR)/input.pp.rs

View File

@ -0,0 +1,16 @@
// 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.
#![feature(macro_rules)]
// minimal junk
#![no_std]
fn bar /* 62#0 */() { let x /* 59#2 */ = 1; y /* 61#4 */ + x /* 59#5 */ }

View File

@ -0,0 +1,22 @@
// 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.
#![feature(macro_rules)]
// minimal junk
#![no_std]
macro_rules! foo {
($x: ident) => { y + $x }
}
fn bar() {
let x = 1;
foo!(x)
}