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}
;
19 use std
::hashmap
::HashMap
;
25 pub fn path_name_i(idents
: &[ident
]) -> ~str {
26 // FIXME: Bad copies (#2543 -- same for everything else that says "bad")
27 idents
.map(|i
| token
::interner_get(i
.name
)).connect("::")
30 pub fn path_to_ident(p
: @Path
) -> ident { copy *p.idents.last() }
32 pub fn local_def(id
: node_id
) -> def_id
{
33 ast
::def_id { crate: local_crate, node: id }
36 pub fn is_local(did
: ast
::def_id
) -> bool { did.crate == local_crate }
38 pub fn stmt_id(s
: &stmt
) -> node_id
{
40 stmt_decl(_
, id
) => id
,
41 stmt_expr(_
, id
) => id
,
42 stmt_semi(_
, id
) => id
,
43 stmt_mac(*) => fail
!("attempted to analyze unexpanded stmt")
47 pub fn variant_def_ids(d
: def
) -> Option
<(def_id
, def_id
)> {
49 def_variant(enum_id
, var_id
) => {
50 Some((enum_id
, var_id
))
56 pub fn def_id_of_def(d
: def
) -> def_id
{
58 def_fn(id
, _
) | def_static_method(id
, _
, _
) | def_mod(id
) |
59 def_foreign_mod(id
) | def_static(id
, _
) |
60 def_variant(_
, id
) | def_ty(id
) | def_ty_param(id
, _
) |
61 def_use(id
) | def_struct(id
) | def_trait(id
) | def_method(id
, _
) => {
64 def_arg(id
, _
) | def_local(id
, _
) | def_self(id
, _
) | def_self_ty(id
)
65 | def_upvar(id
, _
, _
, _
) | def_binding(id
, _
) | def_region(id
)
66 | def_typaram_binder(id
) | def_label(id
) => {
70 def_prim_ty(_
) => fail
!()
74 pub fn binop_to_str(op
: binop
) -> ~str {
77 subtract
=> return ~"-",
83 bitxor
=> return ~"^",
84 bitand
=> return ~"&",
97 pub fn binop_to_method_name(op
: binop
) -> Option
<~str> {
99 add
=> return Some(~"add"),
100 subtract
=> return Some(~"sub"),
101 mul
=> return Some(~"mul"),
102 div
=> return Some(~"div"),
103 rem
=> return Some(~"rem"),
104 bitxor
=> return Some(~"bitxor"),
105 bitand
=> return Some(~"bitand"),
106 bitor
=> return Some(~"bitor"),
107 shl
=> return Some(~"shl"),
108 shr
=> return Some(~"shr"),
109 lt
=> return Some(~"lt"),
110 le
=> return Some(~"le"),
111 ge
=> return Some(~"ge"),
112 gt
=> return Some(~"gt"),
113 eq
=> return Some(~"eq"),
114 ne
=> return Some(~"ne"),
115 and
| or
=> return None
119 pub fn lazy_binop(b
: binop
) -> bool
{
127 pub fn is_shift_binop(b
: binop
) -> bool
{
135 pub fn unop_to_str(op
: unop
) -> ~str {
137 box(mt
) => if mt
== m_mutbl { ~"@mut " }
else { ~"@" }
,
145 pub fn is_path(e
: @expr
) -> bool
{
146 return match e
.node { expr_path(_) => true, _ => false }
;
149 pub fn int_ty_to_str(t
: int_ty
) -> ~str {
151 ty_char
=> ~"u8", // ???
160 pub fn int_ty_max(t
: int_ty
) -> u64 {
164 ty_i
| ty_char
| ty_i32
=> 0x80000000u64, // actually ni about ty_i
165 ty_i64
=> 0x8000000000000000u64
169 pub fn uint_ty_to_str(t
: uint_ty
) -> ~str {
179 pub fn uint_ty_max(t
: uint_ty
) -> u64 {
183 ty_u
| ty_u32
=> 0xffffffffu64, // actually ni about ty_u
184 ty_u64
=> 0xffffffffffffffffu64
188 pub fn float_ty_to_str(t
: float_ty
) -> ~str {
189 match t { ty_f => ~"f", ty_f32 => ~"f32", ty_f64 => ~"f64" }
192 pub fn is_call_expr(e
: @expr
) -> bool
{
193 match e
.node { expr_call(*) => true, _ => false }
196 pub fn block_from_expr(e
: @expr
) -> blk
{
197 let blk_
= default_block(~[], option
::Some
::<@expr
>(e
), e
.id
);
198 return spanned {node: blk_, span: e.span}
;
201 pub fn default_block(
203 expr1
: Option
<@expr
>,
215 pub fn ident_to_path(s
: span
, i
: ident
) -> @Path
{
216 @ast
::Path
{ span
: s
,
223 pub fn ident_to_pat(id
: node_id
, s
: span
, i
: ident
) -> @pat
{
225 node
: pat_ident(bind_infer
, ident_to_path(s
, i
), None
),
229 pub fn is_unguarded(a
: &arm
) -> bool
{
236 pub fn unguarded_pat(a
: &arm
) -> Option
<~[@pat
]> {
237 if is_unguarded(a
) { Some(/* FIXME (#2543) */ copy a.pats) }
else { None }
240 pub fn public_methods(ms
: ~[@method
]) -> ~[@method
] {
249 // extract a ty_method from a trait_method. if the trait_method is
250 // a default, pull out the useful fields to make a ty_method
251 pub fn trait_method_to_ty_method(method
: &trait_method
) -> ty_method
{
253 required(ref m
) => copy
*m
,
260 generics
: copy m
.generics
,
261 explicit_self
: m
.explicit_self
,
269 pub fn split_trait_methods(trait_methods
: &[trait_method
])
270 -> (~[ty_method
], ~[@method
]) {
273 for trait_methods
.iter().advance
|trt_method
| {
275 required(ref tm
) => reqd
.push(copy
*tm
),
276 provided(m
) => provd
.push(m
)
282 pub fn struct_field_visibility(field
: ast
::struct_field
) -> visibility
{
283 match field
.node
.kind
{
284 ast
::named_field(_
, visibility
) => visibility
,
285 ast
::unnamed_field
=> ast
::public
289 pub trait inlined_item_utils
{
290 fn ident(&self) -> ident
;
291 fn id(&self) -> ast
::node_id
;
292 fn accept
<E
: Copy
>(&self, e
: E
, v
: visit
::vt
<E
>);
295 impl inlined_item_utils
for inlined_item
{
296 fn ident(&self) -> ident
{
298 ii_item(i
) => /* FIXME (#2543) */ copy i
.ident
,
299 ii_foreign(i
) => /* FIXME (#2543) */ copy i
.ident
,
300 ii_method(_
, m
) => /* FIXME (#2543) */ copy m
.ident
,
304 fn id(&self) -> ast
::node_id
{
307 ii_foreign(i
) => i
.id
,
308 ii_method(_
, m
) => m
.id
,
312 fn accept
<E
: Copy
>(&self, e
: E
, v
: visit
::vt
<E
>) {
314 ii_item(i
) => (v
.visit_item
)(i
, (e
, v
)),
315 ii_foreign(i
) => (v
.visit_foreign_item
)(i
, (e
, v
)),
316 ii_method(_
, m
) => visit
::visit_method_helper(m
, (e
, v
)),
321 /* True if d is either a def_self, or a chain of def_upvars
322 referring to a def_self */
323 pub fn is_self(d
: ast
::def
) -> bool
{
326 def_upvar(_
, d
, _
, _
) => is_self(*d
),
331 /// Maps a binary operator to its precedence
332 pub fn operator_prec(op
: ast
::binop
) -> uint
{
334 mul
| div
| rem
=> 12u,
335 // 'as' sits between here with 11
336 add
| subtract
=> 10u,
341 lt
| le
| ge
| gt
=> 4u,
348 /// Precedence of the `as` operator, which is a binary operator
349 /// not appearing in the prior table.
350 pub static as_prec
: uint
= 11u;
352 pub fn empty_generics() -> Generics
{
353 Generics
{lifetimes
: opt_vec
::Empty
,
354 ty_params
: opt_vec
::Empty
}
357 // ______________________________________________________________________
358 // Enumerating the IDs which appear in an AST
360 #[deriving(Encodable, Decodable)]
361 pub struct id_range
{
367 pub fn max() -> id_range
{
374 pub fn empty(&self) -> bool
{
378 pub fn add(&mut self, id
: node_id
) {
379 self.min
= int
::min(self.min
, id
);
380 self.max
= int
::max(self.max
, id
+ 1);
384 pub fn id_visitor
<T
: Copy
>(vfn
: @
fn(node_id
, T
)) -> visit
::vt
<T
> {
385 let visit_generics
: @
fn(&Generics
, T
) = |generics
, t
| {
386 for generics
.ty_params
.iter().advance
|p
| {
389 for generics
.lifetimes
.iter().advance
|p
| {
393 visit
::mk_vt(@visit
::Visitor
{
394 visit_mod
: |m
, sp
, id
, (t
, vt
)| {
396 visit
::visit_mod(m
, sp
, id
, (t
, vt
));
399 visit_view_item
: |vi
, (t
, vt
)| {
401 view_item_extern_mod(_
, _
, id
) => vfn(id
, copy t
),
402 view_item_use(ref vps
) => {
403 for vps
.iter().advance
|vp
| {
405 view_path_simple(_
, _
, id
) => vfn(id
, copy t
),
406 view_path_glob(_
, id
) => vfn(id
, copy t
),
407 view_path_list(_
, ref paths
, id
) => {
409 for paths
.iter().advance
|p
| {
410 vfn(p
.node
.id
, copy t
);
417 visit
::visit_view_item(vi
, (t
, vt
));
420 visit_foreign_item
: |ni
, (t
, vt
)| {
422 visit
::visit_foreign_item(ni
, (t
, vt
));
425 visit_item
: |i
, (t
, vt
)| {
428 item_enum(ref enum_definition
, _
) =>
429 for (*enum_definition
).variants
.iter().advance
|v
| { vfn(v.node.id, copy t); }
,
432 visit
::visit_item(i
, (t
, vt
));
435 visit_local
: |l
, (t
, vt
)| {
436 vfn(l
.node
.id
, copy t
);
437 visit
::visit_local(l
, (t
, vt
));
439 visit_block
: |b
, (t
, vt
)| {
440 vfn(b
.node
.id
, copy t
);
441 visit
::visit_block(b
, (t
, vt
));
443 visit_stmt
: |s
, (t
, vt
)| {
444 vfn(ast_util
::stmt_id(s
), copy t
);
445 visit
::visit_stmt(s
, (t
, vt
));
447 visit_pat
: |p
, (t
, vt
)| {
449 visit
::visit_pat(p
, (t
, vt
));
452 visit_expr
: |e
, (t
, vt
)| {
454 let r
= e
.get_callee_id();
455 for r
.iter().advance
|callee_id
| {
456 vfn(*callee_id
, copy t
);
460 visit
::visit_expr(e
, (t
, vt
));
463 visit_ty
: |ty
, (t
, vt
)| {
465 ty_path(_
, _
, id
) => vfn(id
, copy t
),
466 _
=> { /* fall through */ }
468 visit
::visit_ty(ty
, (t
, vt
));
471 visit_generics
: |generics
, (t
, vt
)| {
472 visit_generics(generics
, copy t
);
473 visit
::visit_generics(generics
, (t
, vt
));
476 visit_fn
: |fk
, d
, a
, b
, id
, (t
, vt
)| {
480 visit
::fk_item_fn(_
, generics
, _
, _
) => {
481 visit_generics(generics
, copy t
);
483 visit
::fk_method(_
, generics
, m
) => {
484 vfn(m
.self_id
, copy t
);
485 visit_generics(generics
, copy t
);
488 visit
::fk_fn_block
=> {
492 for d
.inputs
.iter().advance
|arg
| {
495 visit
::visit_fn(fk
, d
, a
, b
, id
, (copy t
, vt
));
498 visit_struct_field
: |f
, (t
, vt
)| {
499 vfn(f
.node
.id
, copy t
);
500 visit
::visit_struct_field(f
, (t
, vt
));
503 .. *visit
::default_visitor()
507 pub fn visit_ids_for_inlined_item(item
: &inlined_item
, vfn
: @
fn(node_id
)) {
508 item
.accept((), id_visitor(|id
, ()| vfn(id
)));
511 pub fn compute_id_range(visit_ids_fn
: &fn(@
fn(node_id
))) -> id_range
{
512 let result
= @
mut id_range
::max();
513 do visit_ids_fn
|id
| {
519 pub fn compute_id_range_for_inlined_item(item
: &inlined_item
) -> id_range
{
520 compute_id_range(|f
| visit_ids_for_inlined_item(item
, f
))
523 pub fn is_item_impl(item
: @ast
::item
) -> bool
{
525 item_impl(*) => true,
530 pub fn walk_pat(pat
: @pat
, it
: &fn(@pat
) -> bool
) -> bool
{
536 pat_ident(_
, _
, Some(p
)) => walk_pat(p
, it
),
537 pat_struct(_
, ref fields
, _
) => {
538 fields
.iter().advance(|f
| walk_pat(f
.pat
, |p
| it(p
)))
540 pat_enum(_
, Some(ref s
)) | pat_tup(ref s
) => {
541 s
.iter().advance(|&p
| walk_pat(p
, |p
| it(p
)))
543 pat_box(s
) | pat_uniq(s
) | pat_region(s
) => {
546 pat_vec(ref before
, ref slice
, ref after
) => {
547 before
.iter().advance(|&p
| walk_pat(p
, |p
| it(p
))) &&
548 slice
.iter().advance(|&p
| walk_pat(p
, |p
| it(p
))) &&
549 after
.iter().advance(|&p
| walk_pat(p
, |p
| it(p
)))
551 pat_wild
| pat_lit(_
) | pat_range(_
, _
) | pat_ident(_
, _
, _
) |
558 pub trait EachViewItem
{
559 pub fn each_view_item(&self, f
: @
fn(&ast
::view_item
) -> bool
) -> bool
;
562 impl EachViewItem
for ast
::crate {
563 fn each_view_item(&self, f
: @
fn(&ast
::view_item
) -> bool
) -> bool
{
564 let broke
= @
mut false;
565 let vtor
: visit
::vt
<()> = visit
::mk_simple_visitor(@visit
::SimpleVisitor
{
566 visit_view_item
: |vi
| { *broke = f(vi); }
, ..*visit
::default_simple_visitor()
568 visit
::visit_crate(self, ((), vtor
));
573 pub fn view_path_id(p
: &view_path
) -> node_id
{
575 view_path_simple(_
, _
, id
) |
576 view_path_glob(_
, id
) |
577 view_path_list(_
, _
, id
) => id
581 /// Returns true if the given struct def is tuple-like; i.e. that its fields
583 pub fn struct_def_is_tuple_like(struct_def
: @ast
::struct_def
) -> bool
{
584 struct_def
.ctor_id
.is_some()
587 pub fn visibility_to_privacy(visibility
: visibility
) -> Privacy
{
590 inherited
| private
=> Private
594 pub fn variant_visibility_to_privacy(visibility
: visibility
,
595 enclosing_is_public
: bool
)
597 if enclosing_is_public
{
599 public
| inherited
=> Public
,
603 visibility_to_privacy(visibility
)
613 /// Returns true if the given pattern consists solely of an identifier
614 /// and false otherwise.
615 pub fn pat_is_ident(pat
: @ast
::pat
) -> bool
{
617 ast
::pat_ident(*) => true,
624 /// Construct an identifier with the given name and an empty context:
625 pub fn new_ident(name
: Name
) -> ident { ident {name: name, ctxt: 0}
}
627 /// Extend a syntax context with a given mark
628 pub fn new_mark(m
:Mrk
, tail
:SyntaxContext
) -> SyntaxContext
{
629 new_mark_internal(m
,tail
,get_sctable())
632 // Extend a syntax context with a given mark and table
633 // FIXME #4536 : currently pub to allow testing
634 pub fn new_mark_internal(m
:Mrk
, tail
:SyntaxContext
,table
:&mut SCTable
)
637 // FIXME #5074 : can't use more natural style because we're missing
638 // flow-sensitivity. Results in two lookups on a hash table hit.
639 // also applies to new_rename_internal, below.
640 // let try_lookup = table.mark_memo.find(&key);
641 match table
.mark_memo
.contains_key(&key
) {
643 let new_idx
= idx_push(&mut table
.table
,Mark(m
,tail
));
644 table
.mark_memo
.insert(key
,new_idx
);
648 match table
.mark_memo
.find(&key
) {
649 None
=> fail
!(~"internal error: key disappeared 2013042901"),
650 Some(idxptr
) => {*idxptr}
656 /// Extend a syntax context with a given rename
657 pub fn new_rename(id
:ident
, to
:Name
, tail
:SyntaxContext
) -> SyntaxContext
{
658 new_rename_internal(id
, to
, tail
, get_sctable())
661 // Extend a syntax context with a given rename and sctable
662 // FIXME #4536 : currently pub to allow testing
663 pub fn new_rename_internal(id
:ident
, to
:Name
, tail
:SyntaxContext
, table
: &mut SCTable
)
665 let key
= (tail
,id
,to
);
667 //let try_lookup = table.rename_memo.find(&key);
668 match table
.rename_memo
.contains_key(&key
) {
670 let new_idx
= idx_push(&mut table
.table
,Rename(id
,to
,tail
));
671 table
.rename_memo
.insert(key
,new_idx
);
675 match table
.rename_memo
.find(&key
) {
676 None
=> fail
!(~"internal error: key disappeared 2013042902"),
677 Some(idxptr
) => {*idxptr}
683 /// Make a fresh syntax context table with EmptyCtxt in slot zero
684 /// and IllegalCtxt in slot one.
685 // FIXME #4536 : currently pub to allow testing
686 pub fn new_sctable_internal() -> SCTable
{
688 table
: ~[EmptyCtxt
,IllegalCtxt
],
689 mark_memo
: HashMap
::new(),
690 rename_memo
: HashMap
::new()
694 // fetch the SCTable from TLS, create one if it doesn't yet exist.
695 pub fn get_sctable() -> @
mut SCTable
{
697 let sctable_key
= (cast
::transmute
::<(uint
, uint
),
698 &fn:Copy(v
: @@
mut SCTable
)>(
700 match local_data
::local_data_get(sctable_key
) {
702 let new_table
= @@
mut new_sctable_internal();
703 local_data
::local_data_set(sctable_key
,new_table
);
711 /// Add a value to the end of a vec, return its index
712 fn idx_push
<T
>(vec
: &mut ~[T
], val
: T
) -> uint
{
717 /// Resolve a syntax object to a name, per MTWT.
718 pub fn resolve(id
: ident
) -> Name
{
719 resolve_internal(id
, get_sctable())
722 // Resolve a syntax object to a name, per MTWT.
723 // FIXME #4536 : currently pub to allow testing
724 pub fn resolve_internal(id
: ident
, table
: &mut SCTable
) -> Name
{
725 match table
.table
[id
.ctxt
] {
726 EmptyCtxt
=> id
.name
,
727 // ignore marks here:
728 Mark(_
,subctxt
) => resolve_internal(ident{name:id.name, ctxt: subctxt}
,table
),
729 // do the rename if necessary:
730 Rename(ident{name,ctxt}
,toname
,subctxt
) => {
731 // this could be cached or computed eagerly:
732 let resolvedfrom
= resolve_internal(ident{name:name,ctxt:ctxt}
,table
);
733 let resolvedthis
= resolve_internal(ident{name:id.name,ctxt:subctxt}
,table
);
734 if ((resolvedthis
== resolvedfrom
)
735 && (marksof(ctxt
,resolvedthis
,table
)
736 == marksof(subctxt
,resolvedthis
,table
))) {
742 IllegalCtxt() => fail
!(~"expected resolvable context, got IllegalCtxt")
746 /// Compute the marks associated with a syntax context.
747 // it's not clear to me whether it's better to use a [] mutable
748 // vector or a cons-list for this.
749 pub fn marksof(ctxt
: SyntaxContext
, stopname
: Name
, table
: &SCTable
) -> ~[Mrk
] {
750 let mut result
= ~[];
751 let mut loopvar
= ctxt
;
753 match table
.table
[loopvar
] {
754 EmptyCtxt
=> {return result;}
,
756 xorPush(&mut result
,mark
);
759 Rename(_
,name
,tl
) => {
760 // see MTWT for details on the purpose of the stopname.
761 // short version: it prevents duplication of effort.
762 if (name
== stopname
) {
768 IllegalCtxt
=> fail
!(~"expected resolvable context, got IllegalCtxt")
773 /// Push a name... unless it matches the one on top, in which
774 /// case pop and discard (so two of the same marks cancel)
775 pub fn xorPush(marks
: &mut ~[uint
], mark
: uint
) {
776 if ((marks
.len() > 0) && (getLast(marks
) == mark
)) {
783 // get the last element of a mutable array.
784 // FIXME #4903: , must be a separate procedure for now.
785 pub fn getLast(arr
: &~[Mrk
]) -> uint
{
796 #[test] fn xorpush_test () {
799 assert_eq
!(copy s
,~[14]);
801 assert_eq
!(copy s
,~[]);
803 assert_eq
!(copy s
,~[14]);
805 assert_eq
!(copy s
,~[14,15]);
807 assert_eq
!(copy s
,~[14,15,16]);
809 assert_eq
!(copy s
,~[14,15]);
811 assert_eq
!(copy s
,~[14]);
814 // convert a list of uints to an @[ident]
815 // (ignores the interner completely)
816 fn uints_to_idents (uints
: &~[uint
]) -> @
~[ident
] {
817 @uints
.map(|u
| ident {name:*u, ctxt: empty_ctxt}
)
820 fn id (u
: uint
, s
: SyntaxContext
) -> ident
{
821 ident{name:u, ctxt: s}
824 // because of the SCTable, I now need a tidy way of
825 // creating syntax objects. Sigh.
832 // unfold a vector of TestSC values into a SCTable,
833 // returning the resulting index
834 fn unfold_test_sc(tscs
: ~[TestSC
], tail
: SyntaxContext
, table
: &mut SCTable
)
836 tscs
.rev_iter().fold(tail
, |tail
: SyntaxContext
, tsc
: &TestSC
|
838 M(mrk
) => new_mark_internal(mrk
,tail
,table
),
839 R(ident
,name
) => new_rename_internal(ident
,name
,tail
,table
)}})
842 // gather a SyntaxContext back into a vector of TestSCs
843 fn refold_test_sc(mut sc
: SyntaxContext
, table
: &SCTable
) -> ~[TestSC
] {
844 let mut result
= ~[];
846 match table
.table
[sc
] {
847 EmptyCtxt
=> {return result;}
,
853 Rename(id
,name
,tail
) => {
854 result
.push(R(id
,name
));
858 IllegalCtxt
=> fail
!("expected resolvable context, got IllegalCtxt")
863 #[test] fn test_unfold_refold(){
864 let mut t
= new_sctable_internal();
866 let test_sc
= ~[M(3),R(id(101,0),14),M(9)];
867 assert_eq
!(unfold_test_sc(copy test_sc
,empty_ctxt
,&mut t
),4);
868 assert_eq
!(t
.table
[2],Mark(9,0));
869 assert_eq
!(t
.table
[3],Rename(id(101,0),14,2));
870 assert_eq
!(t
.table
[4],Mark(3,3));
871 assert_eq
!(refold_test_sc(4,&t
),test_sc
);
874 // extend a syntax context with a sequence of marks given
875 // in a vector. v[0] will be the outermost mark.
876 fn unfold_marks(mrks
:~[Mrk
],tail
:SyntaxContext
,table
: &mut SCTable
) -> SyntaxContext
{
877 mrks
.rev_iter().fold(tail
, |tail
:SyntaxContext
, mrk
:&Mrk
|
878 {new_mark_internal(*mrk,tail,table)}
)
881 #[test] fn unfold_marks_test() {
882 let mut t
= new_sctable_internal();
884 assert_eq
!(unfold_marks(~[3,7],empty_ctxt
,&mut t
),3);
885 assert_eq
!(t
.table
[2],Mark(7,0));
886 assert_eq
!(t
.table
[3],Mark(3,2));
889 #[test] fn test_marksof () {
892 let mut t
= new_sctable_internal();
893 assert_eq
!(marksof (empty_ctxt
,stopname
,&t
),~[]);
894 // FIXME #5074: ANF'd to dodge nested calls
895 { let ans
= unfold_marks(~[4,98],empty_ctxt
,&mut t
);
896 assert_eq
! (marksof (ans
,stopname
,&t
),~[4,98]);}
898 { let ans
= unfold_marks(~[5,5,16],empty_ctxt
,&mut t
);
899 assert_eq
! (marksof (ans
,stopname
,&t
), ~[16]);}
900 // does nested xoring work?
901 { let ans
= unfold_marks(~[5,10,10,5,16],empty_ctxt
,&mut t
);
902 assert_eq
! (marksof (ans
, stopname
,&t
), ~[16]);}
903 // rename where stop doesn't match:
904 { let chain
= ~[M(9),
906 new_mark_internal (4, empty_ctxt
,&mut t
)),
909 let ans
= unfold_test_sc(chain
,empty_ctxt
,&mut t
);
910 assert_eq
! (marksof (ans
, stopname
, &t
), ~[9,14]);}
911 // rename where stop does match
912 { let name1sc
= new_mark_internal(4, empty_ctxt
, &mut t
);
914 R(id(name1
, name1sc
),
917 let ans
= unfold_test_sc(chain
,empty_ctxt
,&mut t
);
918 assert_eq
! (marksof (ans
, stopname
, &t
), ~[9]); }
922 #[test] fn resolve_tests () {
924 let mut t
= new_sctable_internal();
926 assert_eq
!(resolve_internal(id(a
,empty_ctxt
),&mut t
),a
);
927 // - simple ignored marks
928 { let sc
= unfold_marks(~[1,2,3],empty_ctxt
,&mut t
);
929 assert_eq
!(resolve_internal(id(a
,sc
),&mut t
),a
);}
930 // - orthogonal rename where names don't match
931 { let sc
= unfold_test_sc(~[R(id(50,empty_ctxt
),51),M(12)],empty_ctxt
,&mut t
);
932 assert_eq
!(resolve_internal(id(a
,sc
),&mut t
),a
);}
933 // - rename where names do match, but marks don't
934 { let sc1
= new_mark_internal(1,empty_ctxt
,&mut t
);
935 let sc
= unfold_test_sc(~[R(id(a
,sc1
),50),
939 assert_eq
!(resolve_internal(id(a
,sc
),&mut t
), a
);}
940 // - rename where names and marks match
941 { let sc1
= unfold_test_sc(~[M(1),M(2)],empty_ctxt
,&mut t
);
942 let sc
= unfold_test_sc(~[R(id(a
,sc1
),50),M(1),M(2)],empty_ctxt
,&mut t
);
943 assert_eq
!(resolve_internal(id(a
,sc
),&mut t
), 50); }
944 // - rename where names and marks match by literal sharing
945 { let sc1
= unfold_test_sc(~[M(1),M(2)],empty_ctxt
,&mut t
);
946 let sc
= unfold_test_sc(~[R(id(a
,sc1
),50)],sc1
,&mut t
);
947 assert_eq
!(resolve_internal(id(a
,sc
),&mut t
), 50); }
948 // - two renames of the same var.. can only happen if you use
949 // local-expand to prevent the inner binding from being renamed
950 // during the rename-pass caused by the first:
951 io
::println("about to run bad test");
952 { let sc
= unfold_test_sc(~[R(id(a
,empty_ctxt
),50),
953 R(id(a
,empty_ctxt
),51)],
955 assert_eq
!(resolve_internal(id(a
,sc
),&mut t
), 51); }
956 // the simplest double-rename:
957 { let a_to_a50
= new_rename_internal(id(a
,empty_ctxt
),50,empty_ctxt
,&mut t
);
958 let a50_to_a51
= new_rename_internal(id(a
,a_to_a50
),51,a_to_a50
,&mut t
);
959 assert_eq
!(resolve_internal(id(a
,a50_to_a51
),&mut t
),51);
960 // mark on the outside doesn't stop rename:
961 let sc
= new_mark_internal(9,a50_to_a51
,&mut t
);
962 assert_eq
!(resolve_internal(id(a
,sc
),&mut t
),51);
963 // but mark on the inside does:
964 let a50_to_a51_b
= unfold_test_sc(~[R(id(a
,a_to_a50
),51),
968 assert_eq
!(resolve_internal(id(a
,a50_to_a51_b
),&mut t
),50);}
971 #[test] fn hashing_tests () {
972 let mut t
= new_sctable_internal();
973 assert_eq
!(new_mark_internal(12,empty_ctxt
,&mut t
),2);
974 assert_eq
!(new_mark_internal(13,empty_ctxt
,&mut t
),3);
975 // using the same one again should result in the same index:
976 assert_eq
!(new_mark_internal(12,empty_ctxt
,&mut t
),2);
977 // I'm assuming that the rename table will behave the same....