Skip to content

Instantly share code, notes, and snippets.

@Aatch
Created June 26, 2013 07:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aatch/5865492 to your computer and use it in GitHub Desktop.
Save Aatch/5865492 to your computer and use it in GitHub Desktop.
Visitor impl using a trait & default methods.
#[allow(default_methods)];
extern mod syntax;
use std::os;
use syntax::abi::AbiSet;
use syntax::codemap::span;
use syntax::parse;
use syntax::opt_vec;
use syntax::opt_vec::OptVec;
use syntax::ast;
use syntax::ast::*;
pub enum FnKind<'self> {
// fn foo() or extern "Abi" fn foo()
FnKindItem(&'self ident, &'self Generics, purity, AbiSet),
// fn foo(&self)
FnKindMethod(&'self ident, &'self Generics, &'self method),
// fn@(x, y) { ... }
FnKindAnon(ast::Sigil),
// |x, y| ...
FnKindBlock,
}
static NO_GENERICS : Generics = Generics {
lifetimes: opt_vec::Empty,
ty_params: opt_vec::Empty,
};
impl<'self> FnKind<'self> {
pub fn name(&self) -> ident {
match self {
&FnKindItem(name, _, _, _) |
&FnKindMethod(name, _, _) => *name,
&FnKindAnon(*) | &FnKindBlock(*) => parse::token::special_idents::anon
}
}
pub fn generics<'r>(&'r self) -> &'r Generics {
match self {
&FnKindItem(_, generics, _, _) |
&FnKindMethod(_, generics, _) => generics,
&FnKindAnon(*) | &FnKindBlock(*) => &NO_GENERICS
}
}
}
trait Visitor {
pub fn visit_crate(&mut self, c: &crate) {
self.visit_mod(&c.node.module, c.span, crate_node_id)
}
pub fn visit_mod(&mut self, m: &_mod, sp: span, id: node_id) {
self.visit_mod_contents(m, sp, id)
}
pub fn visit_mod_contents(&mut self, m: &_mod, sp: span, id: node_id) {
for m.view_items.iter().advance |&vi| {
self.visit_view_item(vi);
}
for m.items.iter().advance |&i| {
self.visit_item(i);
}
}
pub fn visit_view_item(&mut self, _vi: @view_item) { }
pub fn visit_item(&mut self, i: @item) {
self.visit_item_contents(i)
}
pub fn visit_item_contents(&mut self, i: @item) {
match i.node {
item_const(t, ex) => {
self.visit_ty(t);
self.visit_expr(ex);
}
item_fn(ref decl, purity, abi, ref generics, ref body) => {
let fk = FnKindItem(&i.ident, generics, purity, abi);
self.visit_fn(&fk, decl, body, i.span, i.id);
}
item_mod(ref m) => self.visit_mod(m, i.span, i.id),
item_foreign_mod(ref nm) => {
for nm.view_items.iter().advance |&vi| {
self.visit_view_item(vi);
}
for nm.items.iter().advance |&fi| {
self.visit_foreign_item(fi);
}
}
item_ty(t, ref params) => {
self.visit_ty(t);
self.visit_generics(params);
}
item_enum(ref enum_definition, ref params) => {
self.visit_generics(params);
self.visit_enum_def(enum_definition, params);
}
item_impl(ref params, ref traits, ty, ref methods) => {
self.visit_generics(params);
for traits.iter().advance |p| {
self.visit_path(p.path);
}
self.visit_ty(ty);
for methods.iter().advance |&m| {
let fk = FnKindMethod(&m.ident, &m.generics, m);
self.visit_fn(&fk, &m.decl, &m.body, m.span, m.id);
}
}
item_struct(struct_def, ref generics) => {
self.visit_generics(generics);
self.visit_struct_def(struct_def, i.ident, generics, i.id);
}
item_trait(ref generics, ref traits, ref methods) => {
self.visit_generics(generics);
for traits.iter().advance |p| {
self.visit_path(p.path);
}
for methods.iter().advance |m| {
self.visit_trait_method(m);
}
}
item_mac(ref m) => self.visit_mac(m)
}
}
pub fn visit_local(&mut self, loc: @local) {
self.visit_local_contents(loc)
}
pub fn visit_local_contents(&mut self, loc: @local) {
self.visit_pat(loc.node.pat);
self.visit_ty(loc.node.ty);
match loc.node.init {
None => (),
Some(ex) => self.visit_expr(ex)
}
}
pub fn visit_enum_def(&mut self, def: &enum_def, params: &Generics) {
for def.variants.iter().advance |vr| {
match vr.node.kind {
tuple_variant_kind(ref args) => {
for args.iter().advance |va| {
self.visit_ty(va.ty);
}
}
struct_variant_kind(struct_def) => {
self.visit_struct_def(struct_def, vr.node.name, params, vr.node.id);
}
}
for vr.node.disr_expr.iter().advance |&ex| {
self.visit_expr(ex)
}
}
}
pub fn visit_ty(&mut self, t: @Ty) {
self.visit_ty_contents(t)
}
pub fn visit_ty_contents(&mut self, t: @Ty) {
match t.node {
ty_box(mt) | ty_uniq(mt) | ty_vec(mt) |
ty_ptr(mt) | ty_rptr(_, mt) => self.visit_ty(mt.ty),
ty_tup(ref ts) => {
for ts.iter().advance |&tt| {
self.visit_ty(tt);
}
}
ty_closure(ref f) => {
for f.decl.inputs.iter().advance |a| {
self.visit_ty(a.ty);
}
self.visit_ty(f.decl.output);
self.visit_ty_param_bounds(&f.bounds);
}
ty_bare_fn(ref f) => {
for f.decl.inputs.iter().advance |a| {
self.visit_ty(a.ty);
}
self.visit_ty(f.decl.output);
}
ty_path(p, bounds, _) => {
self.visit_path(p);
self.visit_ty_param_bounds(bounds);
}
ty_fixed_length_vec(ref mt, ex) => {
self.visit_ty(mt.ty);
self.visit_expr(ex);
}
ty_nil | ty_bot | ty_mac(_) | ty_infer => ()
}
}
pub fn visit_path(&mut self, p: @Path) {
self.visit_path_contents(p);
}
pub fn visit_path_contents(&mut self, p: @Path) {
for p.types.iter().advance |&tp| {
self.visit_ty(tp);
}
}
pub fn visit_pat(&mut self, p: @pat) {
self.visit_pat_contents(p)
}
pub fn visit_pat_contents(&mut self, p: @pat) {
match p.node {
pat_enum(path, ref children) => {
self.visit_path(path);
for children.iter().advance |children| {
for children.iter().advance |&child| {
self.visit_pat(child);
}
}
}
pat_struct(path, ref fields, _) => {
self.visit_path(path);
for fields.iter().advance |f| {
self.visit_pat(f.pat);
}
}
pat_tup(ref elts) => {
for elts.iter().advance |&elt| {
self.visit_pat(elt);
}
}
pat_box(inner) | pat_uniq(inner) | pat_region(inner) => self.visit_pat(inner),
pat_ident(_, path, ref inner) => {
self.visit_path(path);
for inner.iter().advance |&subpat| {
self.visit_pat(subpat);
}
}
pat_lit(ex) => self.visit_expr(ex),
pat_range(e1, e2) => {
self.visit_expr(e1);
self.visit_expr(e2);
}
pat_wild => (),
pat_vec(ref before, ref slice, ref after) => {
for before.iter().advance |&elt| {
self.visit_pat(elt);
}
for slice.iter().advance |&elt| {
self.visit_pat(elt);
}
for after.iter().advance |&elt| {
self.visit_pat(elt);
}
}
}
}
pub fn visit_foreign_item(&mut self, fi: @foreign_item) {
self.visit_foreign_item_contents(fi)
}
pub fn visit_foreign_item_contents(&mut self, fi: @foreign_item) {
match fi.node {
foreign_item_fn(ref fd, _, ref generics) => {
self.visit_fn_decl(fd);
self.visit_generics(generics);
}
foreign_item_const(t) => {
self.visit_ty(t);
}
}
}
pub fn visit_ty_param_bounds(&mut self, bounds: &OptVec<TyParamBound>) {
self.visit_ty_param_bounds_contents(bounds);
}
pub fn visit_ty_param_bounds_contents(&mut self, bounds: &OptVec<TyParamBound>) {
for bounds.iter().advance |bound| {
match bound {
&TraitTyParamBound(ty) => self.visit_path(ty.path),
&RegionTyParamBound => ()
}
}
}
pub fn visit_generics(&mut self, generics: &Generics) {
self.visit_generics_contents(generics)
}
pub fn visit_generics_contents(&mut self, generics: &Generics) {
for generics.ty_params.iter().advance |tp| {
self.visit_ty_param_bounds(tp.bounds);
}
}
pub fn visit_fn_decl(&mut self, fd: &fn_decl) {
self.visit_fn_decl_contents(fd)
}
pub fn visit_fn_decl_contents(&mut self, fd: &fn_decl) {
for fd.inputs.iter().advance |a| {
self.visit_pat(a.pat);
self.visit_ty(a.ty);
}
self.visit_ty(fd.output);
}
pub fn visit_fn(&mut self, fk: &FnKind, decl: &fn_decl, body: &blk, sp: span, id: node_id) {
self.visit_fn_contents(fk, decl, body, sp, id)
}
pub fn visit_fn_contents(&mut self, fk: &FnKind, decl: &fn_decl, body: &blk, _sp: span,
_id: node_id) {
self.visit_fn_decl(decl);
let generics = fk.generics();
self.visit_generics(generics);
self.visit_block(body);
}
pub fn visit_ty_method(&mut self, meth: &ty_method) {
self.visit_ty_method_contents(meth);
}
pub fn visit_ty_method_contents(&mut self, meth: &ty_method) {
for meth.decl.inputs.iter().advance |a| {
self.visit_ty(a.ty);
}
self.visit_generics(&meth.generics);
self.visit_ty(meth.decl.output);
}
pub fn visit_trait_method(&mut self, m: &trait_method) {
self.visit_trait_method_contents(m)
}
pub fn visit_trait_method_contents(&mut self, m: &trait_method) {
match m {
&required(ref ty_m) => self.visit_ty_method(ty_m),
&provided(m) => {
let fk = FnKindMethod(&m.ident, &m.generics, m);
self.visit_fn(&fk, &m.decl, &m.body, m.span, m.id);
}
}
}
pub fn visit_struct_def(&mut self, sd: @struct_def, nm: ast::ident,
generics: &Generics, id: node_id) {
self.visit_struct_def_contents(sd, nm, generics, id)
}
pub fn visit_struct_def_contents(&mut self, sd: @struct_def, _nm: ast::ident,
_generics: &Generics, _id: node_id) {
for sd.fields.iter().advance |&f| {
self.visit_struct_field(f)
}
}
pub fn visit_struct_field(&mut self, sf: @struct_field) {
self.visit_struct_field_contents(sf)
}
pub fn visit_struct_field_contents(&mut self, sf: @struct_field) {
self.visit_ty(sf.node.ty)
}
pub fn visit_struct_method(&mut self, m: @method) {
self.visit_struct_method_contents(m)
}
pub fn visit_struct_method_contents(&mut self, m: @method) {
let fk = FnKindMethod(&m.ident, &m.generics, m);
self.visit_fn(&fk, &m.decl, &m.body, m.span, m.id);
}
pub fn visit_block(&mut self, b: &blk) {
self.visit_block_contents(b)
}
pub fn visit_block_contents(&mut self, b: &blk) {
for b.node.view_items.iter().advance |&vi| {
self.visit_view_item(vi);
}
for b.node.stmts.iter().advance |&s| {
self.visit_stmt(s);
}
match b.node.expr {
Some(ex) => self.visit_expr(ex),
None => ()
}
}
pub fn visit_stmt(&mut self, s: @stmt) {
self.visit_stmt_contents(s)
}
pub fn visit_stmt_contents(&mut self, s: @stmt) {
match s.node {
stmt_decl(d, _) => self.visit_decl(d),
stmt_semi(ex,_) | stmt_expr(ex, _) => self.visit_expr(ex),
stmt_mac(ref mac, _) => self.visit_mac(mac),
}
}
pub fn visit_decl(&mut self, d: @decl) {
self.visit_decl_content(d)
}
pub fn visit_decl_content(&mut self, d: @decl) {
match d.node {
decl_local(ref loc) => self.visit_local(*loc),
decl_item(it) => self.visit_item(it)
}
}
pub fn visit_mac(&mut self, _m: &mac) { }
pub fn visit_expr(&mut self, ex: @expr) {
self.visit_expr_contents(ex)
}
pub fn visit_expr_contents(&mut self, ex: @expr) {
match ex.node {
expr_vstore(x, _) => self.visit_expr(ex),
expr_vec(ref es, _) => {
for es.iter().advance |&ex| {
self.visit_expr(ex)
}
}
_ => ()
}
self.visit_expr_post(ex)
}
pub fn visit_expr_post(&mut self, ex: @expr) { }
pub fn visit_arm(&mut self, a: &arm) {
self.visit_arm_contents(a)
}
pub fn visit_arm_contents(&mut self, a: &arm) {
}
}
fn main() {
let sess = parse::new_parse_sess(None);
let path = GenericPath::from_str(os::args()[1]);
let crate = parse::parse_crate_from_file(&path, ~[], sess);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment