1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
14 use codemap::{span, spanned};
21 pub fn path_name_i(idents: &[ident], intr: @token::ident_interner) -> ~str {
22 // FIXME: Bad copies (#2543 -- same for everything else that says "bad")
23 str::connect(idents.map(|i| copy *intr.get(*i)), ~"::")
27 pub fn path_to_ident(p: @Path) -> ident { copy *p.idents.last() }
29 pub fn local_def(id: node_id) -> def_id {
30 ast::def_id { crate: local_crate, node: id }
33 pub fn is_local(did: ast::def_id) -> bool { did.crate == local_crate }
35 pub fn stmt_id(s: &stmt) -> node_id {
37 stmt_decl(_, id) => id,
38 stmt_expr(_, id) => id,
39 stmt_semi(_, id) => id,
40 stmt_mac(*) => fail!(~"attempted to analyze unexpanded stmt")
44 pub fn variant_def_ids(d: def) -> (def_id, def_id) {
46 def_variant(enum_id, var_id) => {
47 return (enum_id, var_id);
49 _ => fail!(~"non-variant in variant_def_ids")
53 pub fn def_id_of_def(d: def) -> def_id {
55 def_fn(id, _) | def_static_method(id, _, _) | def_mod(id) |
56 def_foreign_mod(id) | def_const(id) |
57 def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
58 def_use(id) | def_struct(id) | def_trait(id) => {
61 def_arg(id, _) | def_local(id, _) | def_self(id, _) | def_self_ty(id)
62 | def_upvar(id, _, _, _) | def_binding(id, _) | def_region(id)
63 | def_typaram_binder(id) | def_label(id) => {
67 def_prim_ty(_) => fail!()
71 pub fn binop_to_str(op: binop) -> ~str {
74 subtract => return ~"-",
80 bitxor => return ~"^",
81 bitand => return ~"&",
94 pub fn binop_to_method_name(op: binop) -> Option<~str> {
96 add => return Some(~"add"),
97 subtract => return Some(~"sub"),
98 mul => return Some(~"mul"),
99 div => return Some(~"div"),
100 rem => return Some(~"rem"),
101 bitxor => return Some(~"bitxor"),
102 bitand => return Some(~"bitand"),
103 bitor => return Some(~"bitor"),
104 shl => return Some(~"shl"),
105 shr => return Some(~"shr"),
106 lt => return Some(~"lt"),
107 le => return Some(~"le"),
108 ge => return Some(~"ge"),
109 gt => return Some(~"gt"),
110 eq => return Some(~"eq"),
111 ne => return Some(~"ne"),
112 and | or => return None
116 pub fn lazy_binop(b: binop) -> bool {
124 pub fn is_shift_binop(b: binop) -> bool {
132 pub fn unop_to_str(op: unop) -> ~str {
134 box(mt) => if mt == m_mutbl { ~"@mut " } else { ~"@" },
135 uniq(mt) => if mt == m_mutbl { ~"~mut " } else { ~"~" },
142 pub fn is_path(e: @expr) -> bool {
143 return match e.node { expr_path(_) => true, _ => false };
146 pub fn int_ty_to_str(t: int_ty) -> ~str {
148 ty_char => ~"u8", // ???
157 pub fn int_ty_max(t: int_ty) -> u64 {
161 ty_i | ty_char | ty_i32 => 0x80000000u64, // actually ni about ty_i
162 ty_i64 => 0x8000000000000000u64
166 pub fn uint_ty_to_str(t: uint_ty) -> ~str {
176 pub fn uint_ty_max(t: uint_ty) -> u64 {
180 ty_u | ty_u32 => 0xffffffffu64, // actually ni about ty_u
181 ty_u64 => 0xffffffffffffffffu64
185 pub fn float_ty_to_str(t: float_ty) -> ~str {
186 match t { ty_f => ~"f", ty_f32 => ~"f32", ty_f64 => ~"f64" }
189 pub fn is_call_expr(e: @expr) -> bool {
190 match e.node { expr_call(_, _, _) => true, _ => false }
193 // This makes def_id hashable
194 impl to_bytes::IterBytes for def_id {
196 fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
197 to_bytes::iter_bytes_2(&self.crate, &self.node, lsb0, f);
201 pub fn block_from_expr(e: @expr) -> blk {
202 let blk_ = default_block(~[], option::Some::<@expr>(e), e.id);
203 return spanned {node: blk_, span: e.span};
206 pub fn default_block(
208 expr1: Option<@expr>,
220 pub fn ident_to_path(s: span, i: ident) -> @Path {
221 @ast::Path { span: s,
228 pub fn ident_to_pat(id: node_id, s: span, i: ident) -> @pat {
230 node: pat_ident(bind_by_copy, ident_to_path(s, i), None),
234 pub fn is_unguarded(a: &arm) -> bool {
241 pub fn unguarded_pat(a: &arm) -> Option<~[@pat]> {
242 if is_unguarded(a) { Some(/* FIXME (#2543) */ copy a.pats) } else { None }
245 pub fn public_methods(ms: ~[@method]) -> ~[@method] {
254 // extract a ty_method from a trait_method. if the trait_method is
255 // a default, pull out the useful fields to make a ty_method
256 pub fn trait_method_to_ty_method(method: &trait_method) -> ty_method {
258 required(ref m) => copy *m,
265 generics: copy m.generics,
274 pub fn split_trait_methods(trait_methods: &[trait_method])
275 -> (~[ty_method], ~[@method]) {
276 let mut reqd = ~[], provd = ~[];
277 for trait_methods.each |trt_method| {
279 required(ref tm) => reqd.push(copy *tm),
280 provided(m) => provd.push(m)
286 pub fn struct_field_visibility(field: ast::struct_field) -> visibility {
287 match field.node.kind {
288 ast::named_field(_, _, visibility) => visibility,
289 ast::unnamed_field => ast::public
293 pub trait inlined_item_utils {
294 fn ident(&self) -> ident;
295 fn id(&self) -> ast::node_id;
296 fn accept<E: Copy>(&self, e: E, v: visit::vt<E>);
299 impl inlined_item_utils for inlined_item {
300 fn ident(&self) -> ident {
302 ii_item(i) => /* FIXME (#2543) */ copy i.ident,
303 ii_foreign(i) => /* FIXME (#2543) */ copy i.ident,
304 ii_method(_, m) => /* FIXME (#2543) */ copy m.ident,
308 fn id(&self) -> ast::node_id {
311 ii_foreign(i) => i.id,
312 ii_method(_, m) => m.id,
316 fn accept<E: Copy>(&self, e: E, v: visit::vt<E>) {
318 ii_item(i) => (v.visit_item)(i, e, v),
319 ii_foreign(i) => (v.visit_foreign_item)(i, e, v),
320 ii_method(_, m) => visit::visit_method_helper(m, e, v),
325 /* True if d is either a def_self, or a chain of def_upvars
326 referring to a def_self */
327 pub fn is_self(d: ast::def) -> bool {
330 def_upvar(_, d, _, _) => is_self(*d),
335 /// Maps a binary operator to its precedence
336 pub fn operator_prec(op: ast::binop) -> uint {
338 mul | div | rem => 12u,
339 // 'as' sits between here with 11
340 add | subtract => 10u,
345 lt | le | ge | gt => 4u,
352 /// Precedence of the `as` operator, which is a binary operator
353 /// not appearing in the prior table.
354 pub static as_prec: uint = 11u;
356 pub fn empty_generics() -> Generics {
357 Generics {lifetimes: opt_vec::Empty,
358 ty_params: opt_vec::Empty}
361 // ______________________________________________________________________
362 // Enumerating the IDs which appear in an AST
366 pub struct id_range {
371 pub fn empty(range: id_range) -> bool {
372 range.min >= range.max
375 pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> {
376 let visit_generics: @fn(&Generics) = |generics| {
377 for generics.ty_params.each |p| {
380 for generics.lifetimes.each |p| {
384 visit::mk_simple_visitor(@visit::SimpleVisitor {
385 visit_mod: |_m, _sp, id| vfn(id),
387 visit_view_item: |vi| {
389 view_item_extern_mod(_, _, id) => vfn(id),
390 view_item_use(ref vps) => {
393 view_path_simple(_, _, id) => vfn(id),
394 view_path_glob(_, id) => vfn(id),
395 view_path_list(_, _, id) => vfn(id)
402 visit_foreign_item: |ni| vfn(ni.id),
407 item_enum(ref enum_definition, _) =>
408 for (*enum_definition).variants.each |v| { vfn(v.node.id); },
413 visit_local: |l| vfn(l.node.id),
414 visit_block: |b| vfn(b.node.id),
415 visit_stmt: |s| vfn(ast_util::stmt_id(s)),
417 visit_pat: |p| vfn(p.id),
425 visit_expr_post: |_| {},
429 ty_path(_, id) => vfn(id),
430 _ => { /* fall through */ }
434 visit_generics: visit_generics,
436 visit_fn: |fk, d, _, _, id| {
440 visit::fk_item_fn(_, generics, _, _) => {
441 visit_generics(generics);
443 visit::fk_method(_, generics, m) => {
445 visit_generics(generics);
448 visit::fk_fn_block => {
452 for vec::each(d.inputs) |arg| {
457 visit_ty_method: |_| {},
458 visit_trait_method: |_| {},
459 visit_struct_def: |_, _, _, _| {},
460 visit_struct_field: |f| vfn(f.node.id),
461 visit_struct_method: |_| {}
465 pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(node_id)) {
466 item.accept((), id_visitor(vfn));
469 pub fn compute_id_range(visit_ids_fn: &fn(@fn(node_id))) -> id_range {
470 let min = @mut int::max_value;
471 let max = @mut int::min_value;
472 do visit_ids_fn |id| {
473 *min = int::min(*min, id);
474 *max = int::max(*max, id + 1);
476 id_range { min: *min, max: *max }
479 pub fn compute_id_range_for_inlined_item(item: &inlined_item) -> id_range {
480 compute_id_range(|f| visit_ids_for_inlined_item(item, f))
483 pub fn is_item_impl(item: @ast::item) -> bool {
485 item_impl(*) => true,
490 pub fn walk_pat(pat: @pat, it: &fn(@pat)) {
493 pat_ident(_, _, Some(p)) => walk_pat(p, it),
494 pat_struct(_, ref fields, _) => {
495 for fields.each |f| {
499 pat_enum(_, Some(ref s)) | pat_tup(ref s) => {
504 pat_box(s) | pat_uniq(s) | pat_region(s) => {
507 pat_vec(ref before, ref slice, ref after) => {
508 for before.each |p| {
518 pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, _, _) |
519 pat_enum(_, _) => { }
523 pub fn view_path_id(p: @view_path) -> node_id {
525 view_path_simple(_, _, id) |
526 view_path_glob(_, id) |
527 view_path_list(_, _, id) => id
531 /// Returns true if the given struct def is tuple-like; i.e. that its fields
533 pub fn struct_def_is_tuple_like(struct_def: @ast::struct_def) -> bool {
534 struct_def.ctor_id.is_some()
537 pub fn visibility_to_privacy(visibility: visibility) -> Privacy {
540 inherited | private => Private
544 pub fn variant_visibility_to_privacy(visibility: visibility,
545 enclosing_is_public: bool)
547 if enclosing_is_public {
549 public | inherited => Public,
553 visibility_to_privacy(visibility)
565 /// Construct an identifier with the given repr and an empty context:
566 pub fn mk_ident(repr: uint) -> ident { ident {repr: repr, ctxt: 0}}
568 /// Extend a syntax context with a given mark
569 pub fn mk_mark (m:Mrk,ctxt:SyntaxContext,table:&mut SCTable)
571 idx_push(table,Mark(m,ctxt))
574 /// Extend a syntax context with a given rename
575 pub fn mk_rename (id:ident, to:Name, tail:SyntaxContext, table: &mut SCTable)
577 idx_push(table,Rename(id,to,tail))
580 /// Make a fresh syntax context table with EmptyCtxt in slot zero
581 pub fn mk_sctable() -> SCTable { ~[EmptyCtxt] }
583 /// Add a value to the end of a vec, return its index
584 fn idx_push<T>(vec: &mut ~[T], val: T) -> uint {
589 /// Resolve a syntax object to a name, per MTWT.
590 pub fn resolve (id : ident, table : &SCTable) -> Name {
591 match table[id.ctxt] {
592 EmptyCtxt => id.repr,
593 // ignore marks here:
594 Mark(_,subctxt) => resolve (ident{repr:id.repr, ctxt: subctxt},table),
595 // do the rename if necessary:
596 Rename(ident{repr,ctxt},toname,subctxt) => {
597 // this could be cached or computed eagerly:
598 let resolvedfrom = resolve(ident{repr:repr,ctxt:ctxt},table);
599 let resolvedthis = resolve(ident{repr:id.repr,ctxt:subctxt},table);
600 if ((resolvedthis == resolvedfrom)
601 && (marksof (ctxt,resolvedthis,table)
602 == marksof (subctxt,resolvedthis,table))) {
611 /// Compute the marks associated with a syntax context.
612 // it's not clear to me whether it's better to use a [] mutable
613 // vector or a cons-list for this.
614 pub fn marksof(ctxt: SyntaxContext, stopname: Name, table: &SCTable) -> ~[Mrk] {
615 let mut result = ~[];
616 let mut loopvar = ctxt;
618 match table[loopvar] {
619 EmptyCtxt => {return result;},
621 xorPush(&mut result,mark);
624 Rename(_,name,tl) => {
625 // see MTWT for details on the purpose of the stopname.
626 // short version: it prevents duplication of effort.
627 if (name == stopname) {
637 /// Push a name... unless it matches the one on top, in which
638 /// case pop and discard (so two of the same marks cancel)
639 pub fn xorPush(marks: &mut ~[uint], mark: uint) {
640 if ((marks.len() > 0) && (getLast(marks) == mark)) {
647 // get the last element of a mutable array.
648 // FIXME #4903: , must be a separate procedure for now.
649 pub fn getLast(arr: &~[Mrk]) -> uint {
660 #[test] fn xorpush_test () {
669 assert_eq!(s,~[14,15]);
671 assert_eq! (s,~[14,15,16]);
673 assert_eq! (s,~[14,15]);
675 assert_eq! (s,~[14]);
678 // convert a list of uints to an @~[ident]
679 // (ignores the interner completely)
680 fn uints_to_idents (uints: &~[uint]) -> @~[ident] {
681 @uints.map(|u|{ ident {repr:*u, ctxt: empty_ctxt} })
684 fn id (u : uint, s: SyntaxContext) -> ident {
685 ident{repr:u, ctxt: s}
688 // because of the SCTable, I now need a tidy way of
689 // creating syntax objects. Sigh.
696 // unfold a vector of TestSC values into a SCTable,
697 // returning the resulting index
698 fn unfold_test_sc(tscs : ~[TestSC], tail: SyntaxContext, table : &mut SCTable)
700 tscs.foldr(tail, |tsc : &TestSC,tail : SyntaxContext|
702 M(mrk) => mk_mark(mrk,tail,table),
703 R(ident,name) => mk_rename(ident,name,tail,table)}})
706 // gather a SyntaxContext back into a vector of TestSCs
707 fn refold_test_sc(mut sc: SyntaxContext, table : &SCTable) -> ~[TestSC] {
708 let mut result = ~[];
711 EmptyCtxt => {return result;},
717 Rename(id,name,tail) => {
718 result.push(R(id,name));
726 #[test] fn test_unfold_refold(){
727 let mut t = mk_sctable();
729 let test_sc = ~[M(3),R(id(101,0),14),M(9)];
730 assert_eq!(unfold_test_sc(test_sc,empty_ctxt,&mut t),3);
731 assert_eq!(t[1],Mark(9,0));
732 assert_eq!(t[2],Rename(id(101,0),14,1));
733 assert_eq!(t[3],Mark(3,2));
734 assert_eq!(refold_test_sc(3,&t),test_sc);
737 // extend a syntax context with a sequence of marks given
738 // in a vector. v[0] will be the outermost mark.
739 fn unfold_marks(mrks:~[Mrk],tail:SyntaxContext,table: &mut SCTable) -> SyntaxContext {
740 mrks.foldr(tail, |mrk:&Mrk,tail:SyntaxContext|
741 {mk_mark(*mrk,tail,table)})
744 #[test] fn unfold_marks_test() {
745 let mut t = ~[EmptyCtxt];
747 assert_eq!(unfold_marks(~[3,7],empty_ctxt,&mut t),2);
748 assert_eq!(t[1],Mark(7,0));
749 assert_eq!(t[2],Mark(3,1));
752 #[test] fn test_marksof () {
755 let mut t = mk_sctable();
756 assert_eq!(marksof (empty_ctxt,stopname,&t),~[]);
757 // FIXME #5074: ANF'd to dodge nested calls
758 { let ans = unfold_marks(~[4,98],empty_ctxt,&mut t);
759 assert_eq! (marksof (ans,stopname,&t),~[4,98]);}
761 { let ans = unfold_marks(~[5,5,16],empty_ctxt,&mut t);
762 assert_eq! (marksof (ans,stopname,&t), ~[16]);}
763 // does nested xoring work?
764 { let ans = unfold_marks(~[5,10,10,5,16],empty_ctxt,&mut t);
765 assert_eq! (marksof (ans, stopname,&t), ~[16]);}
766 // rename where stop doesn't match:
767 { let chain = ~[M(9),
769 mk_mark (4, empty_ctxt,&mut t)),
772 let ans = unfold_test_sc(chain,empty_ctxt,&mut t);
773 assert_eq! (marksof (ans, stopname, &t), ~[9,14]);}
774 // rename where stop does match
775 { let name1sc = mk_mark(4, empty_ctxt, &mut t);
777 R(id(name1, name1sc),
780 let ans = unfold_test_sc(chain,empty_ctxt,&mut t);
781 assert_eq! (marksof (ans, stopname, &t), ~[9]); }
785 #[test] fn resolve_tests () {
787 let mut t = mk_sctable();
789 assert_eq!(resolve(id(a,empty_ctxt),&t),a);
790 // - simple ignored marks
791 { let sc = unfold_marks(~[1,2,3],empty_ctxt,&mut t);
792 assert_eq!(resolve(id(a,sc),&t),a);}
793 // - orthogonal rename where names don't match
794 { let sc = unfold_test_sc(~[R(id(50,empty_ctxt),51),M(12)],empty_ctxt,&mut t);
795 assert_eq!(resolve(id(a,sc),&t),a);}
796 // - rename where names do match, but marks don't
797 { let sc1 = mk_mark(1,empty_ctxt,&mut t);
798 let sc = unfold_test_sc(~[R(id(a,sc1),50),
802 assert_eq!(resolve(id(a,sc),&t), a);}
803 // - rename where names and marks match
804 { let sc1 = unfold_test_sc(~[M(1),M(2)],empty_ctxt,&mut t);
805 let sc = unfold_test_sc(~[R(id(a,sc1),50),M(1),M(2)],empty_ctxt,&mut t);
806 assert_eq!(resolve(id(a,sc),&t), 50); }
807 // - rename where names and marks match by literal sharing
808 { let sc1 = unfold_test_sc(~[M(1),M(2)],empty_ctxt,&mut t);
809 let sc = unfold_test_sc(~[R(id(a,sc1),50)],sc1,&mut t);
810 assert_eq!(resolve(id(a,sc),&t), 50); }
811 // - two renames of the same var.. can only happen if you use
812 // local-expand to prevent the inner binding from being renamed
813 // during the rename-pass caused by the first:
814 io::println("about to run bad test");
815 { let sc = unfold_test_sc(~[R(id(a,empty_ctxt),50),
816 R(id(a,empty_ctxt),51)],
818 assert_eq!(resolve(id(a,sc),&t), 51); }
819 // the simplest double-rename:
820 { let a_to_a50 = mk_rename(id(a,empty_ctxt),50,empty_ctxt,&mut t);
821 let a50_to_a51 = mk_rename(id(a,a_to_a50),51,a_to_a50,&mut t);
822 assert_eq!(resolve(id(a,a50_to_a51),&t),51);
823 // mark on the outside doesn't stop rename:
824 let sc = mk_mark(9,a50_to_a51,&mut t);
825 assert_eq!(resolve(id(a,sc),&t),51);
826 // but mark on the inside does:
827 let a50_to_a51_b = unfold_test_sc(~[R(id(a,a_to_a50),51),
831 assert_eq!(resolve(id(a,a50_to_a51_b),&t),50);}