]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ast_util.rs
Remove 'Local Variable' comments
[rust.git] / src / libsyntax / ast_util.rs
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.
4 //
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.
10
11 use ast::*;
12 use ast;
13 use ast_util;
14 use codemap::{span, spanned};
15 use parse::token;
16 use visit;
17 use opt_vec;
18
19 use core::to_bytes;
20
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)), ~"::")
24 }
25
26
27 pub fn path_to_ident(p: @Path) -> ident { copy *p.idents.last() }
28
29 pub fn local_def(id: node_id) -> def_id {
30     ast::def_id { crate: local_crate, node: id }
31 }
32
33 pub fn is_local(did: ast::def_id) -> bool { did.crate == local_crate }
34
35 pub fn stmt_id(s: &stmt) -> node_id {
36     match s.node {
37       stmt_decl(_, id) => id,
38       stmt_expr(_, id) => id,
39       stmt_semi(_, id) => id,
40       stmt_mac(*) => fail!(~"attempted to analyze unexpanded stmt")
41     }
42 }
43
44 pub fn variant_def_ids(d: def) -> (def_id, def_id) {
45     match d {
46       def_variant(enum_id, var_id) => {
47         return (enum_id, var_id);
48       }
49       _ => fail!(~"non-variant in variant_def_ids")
50     }
51 }
52
53 pub fn def_id_of_def(d: def) -> def_id {
54     match d {
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) => {
59         id
60       }
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) => {
64         local_def(id)
65       }
66
67       def_prim_ty(_) => fail!()
68     }
69 }
70
71 pub fn binop_to_str(op: binop) -> ~str {
72     match op {
73       add => return ~"+",
74       subtract => return ~"-",
75       mul => return ~"*",
76       div => return ~"/",
77       rem => return ~"%",
78       and => return ~"&&",
79       or => return ~"||",
80       bitxor => return ~"^",
81       bitand => return ~"&",
82       bitor => return ~"|",
83       shl => return ~"<<",
84       shr => return ~">>",
85       eq => return ~"==",
86       lt => return ~"<",
87       le => return ~"<=",
88       ne => return ~"!=",
89       ge => return ~">=",
90       gt => return ~">"
91     }
92 }
93
94 pub fn binop_to_method_name(op: binop) -> Option<~str> {
95     match op {
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
113     }
114 }
115
116 pub fn lazy_binop(b: binop) -> bool {
117     match b {
118       and => true,
119       or => true,
120       _ => false
121     }
122 }
123
124 pub fn is_shift_binop(b: binop) -> bool {
125     match b {
126       shl => true,
127       shr => true,
128       _ => false
129     }
130 }
131
132 pub fn unop_to_str(op: unop) -> ~str {
133     match op {
134       box(mt) => if mt == m_mutbl { ~"@mut " } else { ~"@" },
135       uniq(mt) => if mt == m_mutbl { ~"~mut " } else { ~"~" },
136       deref => ~"*",
137       not => ~"!",
138       neg => ~"-"
139     }
140 }
141
142 pub fn is_path(e: @expr) -> bool {
143     return match e.node { expr_path(_) => true, _ => false };
144 }
145
146 pub fn int_ty_to_str(t: int_ty) -> ~str {
147     match t {
148       ty_char => ~"u8", // ???
149       ty_i => ~"",
150       ty_i8 => ~"i8",
151       ty_i16 => ~"i16",
152       ty_i32 => ~"i32",
153       ty_i64 => ~"i64"
154     }
155 }
156
157 pub fn int_ty_max(t: int_ty) -> u64 {
158     match t {
159       ty_i8 => 0x80u64,
160       ty_i16 => 0x8000u64,
161       ty_i | ty_char | ty_i32 => 0x80000000u64, // actually ni about ty_i
162       ty_i64 => 0x8000000000000000u64
163     }
164 }
165
166 pub fn uint_ty_to_str(t: uint_ty) -> ~str {
167     match t {
168       ty_u => ~"u",
169       ty_u8 => ~"u8",
170       ty_u16 => ~"u16",
171       ty_u32 => ~"u32",
172       ty_u64 => ~"u64"
173     }
174 }
175
176 pub fn uint_ty_max(t: uint_ty) -> u64 {
177     match t {
178       ty_u8 => 0xffu64,
179       ty_u16 => 0xffffu64,
180       ty_u | ty_u32 => 0xffffffffu64, // actually ni about ty_u
181       ty_u64 => 0xffffffffffffffffu64
182     }
183 }
184
185 pub fn float_ty_to_str(t: float_ty) -> ~str {
186     match t { ty_f => ~"f", ty_f32 => ~"f32", ty_f64 => ~"f64" }
187 }
188
189 pub fn is_call_expr(e: @expr) -> bool {
190     match e.node { expr_call(_, _, _) => true, _ => false }
191 }
192
193 // This makes def_id hashable
194 impl to_bytes::IterBytes for def_id {
195     #[inline(always)]
196     fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
197         to_bytes::iter_bytes_2(&self.crate, &self.node, lsb0, f);
198     }
199 }
200
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};
204 }
205
206 pub fn default_block(
207     stmts1: ~[@stmt],
208     expr1: Option<@expr>,
209     id1: node_id
210 ) -> blk_ {
211     ast::blk_ {
212         view_items: ~[],
213         stmts: stmts1,
214         expr: expr1,
215         id: id1,
216         rules: default_blk,
217     }
218 }
219
220 pub fn ident_to_path(s: span, i: ident) -> @Path {
221     @ast::Path { span: s,
222                  global: false,
223                  idents: ~[i],
224                  rp: None,
225                  types: ~[] }
226 }
227
228 pub fn ident_to_pat(id: node_id, s: span, i: ident) -> @pat {
229     @ast::pat { id: id,
230                 node: pat_ident(bind_by_copy, ident_to_path(s, i), None),
231                 span: s }
232 }
233
234 pub fn is_unguarded(a: &arm) -> bool {
235     match a.guard {
236       None => true,
237       _    => false
238     }
239 }
240
241 pub fn unguarded_pat(a: &arm) -> Option<~[@pat]> {
242     if is_unguarded(a) { Some(/* FIXME (#2543) */ copy a.pats) } else { None }
243 }
244
245 pub fn public_methods(ms: ~[@method]) -> ~[@method] {
246     do ms.filtered |m| {
247         match m.vis {
248             public => true,
249             _   => false
250         }
251     }
252 }
253
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 {
257     match *method {
258         required(ref m) => copy *m,
259         provided(ref m) => {
260             ty_method {
261                 ident: m.ident,
262                 attrs: copy m.attrs,
263                 purity: m.purity,
264                 decl: copy m.decl,
265                 generics: copy m.generics,
266                 self_ty: m.self_ty,
267                 id: m.id,
268                 span: m.span,
269             }
270         }
271     }
272 }
273
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| {
278         match *trt_method {
279           required(ref tm) => reqd.push(copy *tm),
280           provided(m) => provd.push(m)
281         }
282     };
283     (reqd, provd)
284 }
285
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
290     }
291 }
292
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>);
297 }
298
299 impl inlined_item_utils for inlined_item {
300     fn ident(&self) -> ident {
301         match *self {
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,
305         }
306     }
307
308     fn id(&self) -> ast::node_id {
309         match *self {
310             ii_item(i) => i.id,
311             ii_foreign(i) => i.id,
312             ii_method(_, m) => m.id,
313         }
314     }
315
316     fn accept<E: Copy>(&self, e: E, v: visit::vt<E>) {
317         match *self {
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),
321         }
322     }
323 }
324
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 {
328   match d {
329     def_self(*)           => true,
330     def_upvar(_, d, _, _) => is_self(*d),
331     _                     => false
332   }
333 }
334
335 /// Maps a binary operator to its precedence
336 pub fn operator_prec(op: ast::binop) -> uint {
337   match op {
338       mul | div | rem   => 12u,
339       // 'as' sits between here with 11
340       add | subtract    => 10u,
341       shl | shr         =>  9u,
342       bitand            =>  8u,
343       bitxor            =>  7u,
344       bitor             =>  6u,
345       lt | le | ge | gt =>  4u,
346       eq | ne           =>  3u,
347       and               =>  2u,
348       or                =>  1u
349   }
350 }
351
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;
355
356 pub fn empty_generics() -> Generics {
357     Generics {lifetimes: opt_vec::Empty,
358               ty_params: opt_vec::Empty}
359 }
360
361 // ______________________________________________________________________
362 // Enumerating the IDs which appear in an AST
363
364 #[auto_encode]
365 #[auto_decode]
366 pub struct id_range {
367     min: node_id,
368     max: node_id,
369 }
370
371 pub fn empty(range: id_range) -> bool {
372     range.min >= range.max
373 }
374
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| {
378             vfn(p.id);
379         }
380         for generics.lifetimes.each |p| {
381             vfn(p.id);
382         }
383     };
384     visit::mk_simple_visitor(@visit::SimpleVisitor {
385         visit_mod: |_m, _sp, id| vfn(id),
386
387         visit_view_item: |vi| {
388             match vi.node {
389               view_item_extern_mod(_, _, id) => vfn(id),
390               view_item_use(ref vps) => {
391                   for vps.each |vp| {
392                       match vp.node {
393                           view_path_simple(_, _, id) => vfn(id),
394                           view_path_glob(_, id) => vfn(id),
395                           view_path_list(_, _, id) => vfn(id)
396                       }
397                   }
398               }
399             }
400         },
401
402         visit_foreign_item: |ni| vfn(ni.id),
403
404         visit_item: |i| {
405             vfn(i.id);
406             match i.node {
407               item_enum(ref enum_definition, _) =>
408                 for (*enum_definition).variants.each |v| { vfn(v.node.id); },
409               _ => ()
410             }
411         },
412
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)),
416         visit_arm: |_| {},
417         visit_pat: |p| vfn(p.id),
418         visit_decl: |_| {},
419
420         visit_expr: |e| {
421             vfn(e.callee_id);
422             vfn(e.id);
423         },
424
425         visit_expr_post: |_| {},
426
427         visit_ty: |t| {
428             match t.node {
429               ty_path(_, id) => vfn(id),
430               _ => { /* fall through */ }
431             }
432         },
433
434         visit_generics: visit_generics,
435
436         visit_fn: |fk, d, _, _, id| {
437             vfn(id);
438
439             match *fk {
440                 visit::fk_item_fn(_, generics, _, _) => {
441                     visit_generics(generics);
442                 }
443                 visit::fk_method(_, generics, m) => {
444                     vfn(m.self_id);
445                     visit_generics(generics);
446                 }
447                 visit::fk_anon(_) |
448                 visit::fk_fn_block => {
449                 }
450             }
451
452             for vec::each(d.inputs) |arg| {
453                 vfn(arg.id)
454             }
455         },
456
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: |_| {}
462     })
463 }
464
465 pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(node_id)) {
466     item.accept((), id_visitor(vfn));
467 }
468
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);
475     }
476     id_range { min: *min, max: *max }
477 }
478
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))
481 }
482
483 pub fn is_item_impl(item: @ast::item) -> bool {
484     match item.node {
485        item_impl(*) => true,
486        _            => false
487     }
488 }
489
490 pub fn walk_pat(pat: @pat, it: &fn(@pat)) {
491     it(pat);
492     match pat.node {
493         pat_ident(_, _, Some(p)) => walk_pat(p, it),
494         pat_struct(_, ref fields, _) => {
495             for fields.each |f| {
496                 walk_pat(f.pat, it)
497             }
498         }
499         pat_enum(_, Some(ref s)) | pat_tup(ref s) => {
500             for s.each |p| {
501                 walk_pat(*p, it)
502             }
503         }
504         pat_box(s) | pat_uniq(s) | pat_region(s) => {
505             walk_pat(s, it)
506         }
507         pat_vec(ref before, ref slice, ref after) => {
508             for before.each |p| {
509                 walk_pat(*p, it)
510             }
511             for slice.each |p| {
512                 walk_pat(*p, it)
513             }
514             for after.each |p| {
515                 walk_pat(*p, it)
516             }
517         }
518         pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, _, _) |
519         pat_enum(_, _) => { }
520     }
521 }
522
523 pub fn view_path_id(p: @view_path) -> node_id {
524     match p.node {
525       view_path_simple(_, _, id) |
526       view_path_glob(_, id) |
527       view_path_list(_, _, id) => id
528     }
529 }
530
531 /// Returns true if the given struct def is tuple-like; i.e. that its fields
532 /// are unnamed.
533 pub fn struct_def_is_tuple_like(struct_def: @ast::struct_def) -> bool {
534     struct_def.ctor_id.is_some()
535 }
536
537 pub fn visibility_to_privacy(visibility: visibility) -> Privacy {
538     match visibility {
539         public => Public,
540         inherited | private => Private
541     }
542 }
543
544 pub fn variant_visibility_to_privacy(visibility: visibility,
545                                      enclosing_is_public: bool)
546                                   -> Privacy {
547     if enclosing_is_public {
548         match visibility {
549             public | inherited => Public,
550             private => Private
551         }
552     } else {
553         visibility_to_privacy(visibility)
554     }
555 }
556
557 #[deriving(Eq)]
558 pub enum Privacy {
559     Private,
560     Public
561 }
562
563 // HYGIENE FUNCTIONS
564
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}}
567
568 /// Extend a syntax context with a given mark
569 pub fn mk_mark (m:Mrk,ctxt:SyntaxContext,table:&mut SCTable)
570     -> SyntaxContext {
571     idx_push(table,Mark(m,ctxt))
572 }
573
574 /// Extend a syntax context with a given rename
575 pub fn mk_rename (id:ident, to:Name, tail:SyntaxContext, table: &mut SCTable)
576     -> SyntaxContext {
577     idx_push(table,Rename(id,to,tail))
578 }
579
580 /// Make a fresh syntax context table with EmptyCtxt in slot zero
581 pub fn mk_sctable() -> SCTable { ~[EmptyCtxt] }
582
583 /// Add a value to the end of a vec, return its index
584 fn idx_push<T>(vec: &mut ~[T], val: T) -> uint {
585     vec.push(val);
586     vec.len() - 1
587 }
588
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))) {
603                 toname
604             } else {
605                 resolvedthis
606             }
607         }
608     }
609 }
610
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;
617     loop {
618         match table[loopvar] {
619             EmptyCtxt => {return result;},
620             Mark(mark,tl) => {
621                 xorPush(&mut result,mark);
622                 loopvar = tl;
623             },
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) {
628                     return result;
629                 } else {
630                     loopvar = tl;
631                 }
632             }
633         }
634     }
635 }
636
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)) {
641         marks.pop();
642     } else {
643         marks.push(mark);
644     }
645 }
646
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 {
650     *arr.last()
651 }
652
653
654 #[cfg(test)]
655 mod test {
656     use ast::*;
657     use super::*;
658     use core::io;
659
660     #[test] fn xorpush_test () {
661         let mut s = ~[];
662         xorPush(&mut s,14);
663         assert_eq!(s,~[14]);
664         xorPush(&mut s,14);
665         assert_eq!(s,~[]);
666         xorPush(&mut s,14);
667         assert_eq!(s,~[14]);
668         xorPush(&mut s,15);
669         assert_eq!(s,~[14,15]);
670         xorPush (&mut s,16);
671         assert_eq! (s,~[14,15,16]);
672         xorPush (&mut s,16);
673         assert_eq! (s,~[14,15]);
674         xorPush (&mut s,15);
675         assert_eq! (s,~[14]);
676     }
677
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} })
682     }
683
684     fn id (u : uint, s: SyntaxContext) -> ident {
685         ident{repr:u, ctxt: s}
686     }
687
688     // because of the SCTable, I now need a tidy way of
689     // creating syntax objects. Sigh.
690     #[deriving(Eq)]
691     enum TestSC {
692         M(Mrk),
693         R(ident,Name)
694     }
695
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)
699         -> SyntaxContext {
700         tscs.foldr(tail, |tsc : &TestSC,tail : SyntaxContext|
701                   {match *tsc {
702                       M(mrk) => mk_mark(mrk,tail,table),
703                       R(ident,name) => mk_rename(ident,name,tail,table)}})
704     }
705
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 = ~[];
709         loop {
710             match table[sc] {
711                 EmptyCtxt => {return result;},
712                 Mark(mrk,tail) => {
713                     result.push(M(mrk));
714                     sc = tail;
715                     loop;
716                 },
717                 Rename(id,name,tail) => {
718                     result.push(R(id,name));
719                     sc = tail;
720                     loop;
721                 }
722             }
723         }
724     }
725
726     #[test] fn test_unfold_refold(){
727         let mut t = mk_sctable();
728
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);
735     }
736
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)})
742     }
743
744     #[test] fn unfold_marks_test() {
745         let mut t = ~[EmptyCtxt];
746
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));
750     }
751
752     #[test] fn test_marksof () {
753         let stopname = 242;
754         let name1 = 243;
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]);}
760         // does xoring work?
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),
768                         R(id(name1,
769                              mk_mark (4, empty_ctxt,&mut t)),
770                           100101102),
771                         M(14)];
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);
776          let chain = ~[M(9),
777                        R(id(name1, name1sc),
778                          stopname),
779                        M(14)];
780          let ans = unfold_test_sc(chain,empty_ctxt,&mut t);
781          assert_eq! (marksof (ans, stopname, &t), ~[9]); }
782     }
783
784
785     #[test] fn resolve_tests () {
786         let a = 40;
787         let mut t = mk_sctable();
788         // - ctxt is MT
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),
799                                    M(1),
800                                    M(2)],
801                                  empty_ctxt,&mut t);
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)],
817                                   empty_ctxt,&mut t);
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),
828                                               M(9)],
829                                            a_to_a50,
830                                            &mut t);
831          assert_eq!(resolve(id(a,a50_to_a51_b),&t),50);}
832     }
833
834 }