1 // Copyright 2012-2013 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.
20 use std::cell::{Cell, RefCell};
21 use std::hashmap::HashMap;
26 pub fn path_name_i(idents: &[Ident]) -> ~str {
27 // FIXME: Bad copies (#2543 -- same for everything else that says "bad")
29 let string = token::get_ident(i.name);
34 // totally scary function: ignores all but the last element, should have
36 pub fn path_to_ident(path: &Path) -> Ident {
37 path.segments.last().unwrap().identifier
40 pub fn local_def(id: NodeId) -> DefId {
41 ast::DefId { crate: LOCAL_CRATE, node: id }
44 pub fn is_local(did: ast::DefId) -> bool { did.crate == LOCAL_CRATE }
46 pub fn stmt_id(s: &Stmt) -> NodeId {
48 StmtDecl(_, id) => id,
49 StmtExpr(_, id) => id,
50 StmtSemi(_, id) => id,
51 StmtMac(..) => fail!("attempted to analyze unexpanded stmt")
55 pub fn variant_def_ids(d: Def) -> Option<(DefId, DefId)> {
57 DefVariant(enum_id, var_id, _) => {
58 Some((enum_id, var_id))
64 pub fn def_id_of_def(d: Def) -> DefId {
66 DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(id) |
67 DefForeignMod(id) | DefStatic(id, _) |
68 DefVariant(_, id, _) | DefTy(id) | DefTyParam(id, _) |
69 DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => {
72 DefArg(id, _) | DefLocal(id, _) | DefSelfTy(id)
73 | DefUpvar(id, _, _, _) | DefBinding(id, _) | DefRegion(id)
74 | DefTyParamBinder(id) | DefLabel(id) => {
78 DefPrimTy(_) => fail!()
82 pub fn binop_to_str(op: BinOp) -> ~str {
89 BiAnd => return ~"&&",
91 BiBitXor => return ~"^",
92 BiBitAnd => return ~"&",
93 BiBitOr => return ~"|",
94 BiShl => return ~"<<",
95 BiShr => return ~">>",
100 BiGe => return ~">=",
105 pub fn binop_to_method_name(op: BinOp) -> Option<~str> {
107 BiAdd => return Some(~"add"),
108 BiSub => return Some(~"sub"),
109 BiMul => return Some(~"mul"),
110 BiDiv => return Some(~"div"),
111 BiRem => return Some(~"rem"),
112 BiBitXor => return Some(~"bitxor"),
113 BiBitAnd => return Some(~"bitand"),
114 BiBitOr => return Some(~"bitor"),
115 BiShl => return Some(~"shl"),
116 BiShr => return Some(~"shr"),
117 BiLt => return Some(~"lt"),
118 BiLe => return Some(~"le"),
119 BiGe => return Some(~"ge"),
120 BiGt => return Some(~"gt"),
121 BiEq => return Some(~"eq"),
122 BiNe => return Some(~"ne"),
123 BiAnd | BiOr => return None
127 pub fn lazy_binop(b: BinOp) -> bool {
135 pub fn is_shift_binop(b: BinOp) -> bool {
143 pub fn unop_to_str(op: UnOp) -> &'static str {
153 pub fn is_path(e: @Expr) -> bool {
154 return match e.node { ExprPath(_) => true, _ => false };
157 pub fn int_ty_to_str(t: IntTy) -> ~str {
167 pub fn int_ty_max(t: IntTy) -> u64 {
171 TyI | TyI32 => 0x80000000u64, // actually ni about TyI
172 TyI64 => 0x8000000000000000u64
176 pub fn uint_ty_to_str(t: UintTy) -> ~str {
186 pub fn uint_ty_max(t: UintTy) -> u64 {
190 TyU | TyU32 => 0xffffffffu64, // actually ni about TyU
191 TyU64 => 0xffffffffffffffffu64
195 pub fn float_ty_to_str(t: FloatTy) -> ~str {
196 match t { TyF32 => ~"f32", TyF64 => ~"f64" }
199 pub fn is_call_expr(e: @Expr) -> bool {
200 match e.node { ExprCall(..) => true, _ => false }
203 pub fn block_from_expr(e: @Expr) -> P<Block> {
214 pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
220 identifier: identifier,
221 lifetimes: opt_vec::Empty,
222 types: opt_vec::Empty,
228 pub fn ident_to_pat(id: NodeId, s: Span, i: Ident) -> @Pat {
230 node: PatIdent(BindByValue(MutImmutable), ident_to_path(s, i), None),
234 pub fn is_unguarded(a: &Arm) -> bool {
241 pub fn unguarded_pat(a: &Arm) -> Option<~[@Pat]> {
243 Some(/* FIXME (#2543) */ a.pats.clone())
249 pub fn public_methods(ms: ~[@Method]) -> ~[@Method] {
250 ms.move_iter().filter(|m| {
258 // extract a TypeMethod from a TraitMethod. if the TraitMethod is
259 // a default, pull out the useful fields to make a TypeMethod
260 pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
262 Required(ref m) => (*m).clone(),
266 attrs: m.attrs.clone(),
269 generics: m.generics.clone(),
270 explicit_self: m.explicit_self,
278 pub fn split_trait_methods(trait_methods: &[TraitMethod])
279 -> (~[TypeMethod], ~[@Method]) {
282 for trt_method in trait_methods.iter() {
284 Required(ref tm) => reqd.push((*tm).clone()),
285 Provided(m) => provd.push(m)
291 pub fn struct_field_visibility(field: ast::StructField) -> Visibility {
292 match field.node.kind {
293 ast::NamedField(_, visibility) => visibility,
294 ast::UnnamedField => ast::Public
298 /// Maps a binary operator to its precedence
299 pub fn operator_prec(op: ast::BinOp) -> uint {
301 // 'as' sits here with 12
302 BiMul | BiDiv | BiRem => 11u,
303 BiAdd | BiSub => 10u,
308 BiLt | BiLe | BiGe | BiGt => 4u,
315 /// Precedence of the `as` operator, which is a binary operator
316 /// not appearing in the prior table.
317 pub static as_prec: uint = 12u;
319 pub fn empty_generics() -> Generics {
320 Generics {lifetimes: opt_vec::Empty,
321 ty_params: opt_vec::Empty}
324 // ______________________________________________________________________
325 // Enumerating the IDs which appear in an AST
327 #[deriving(Encodable, Decodable)]
334 pub fn max() -> IdRange {
341 pub fn empty(&self) -> bool {
345 pub fn add(&mut self, id: NodeId) {
346 self.min = num::min(self.min, id);
347 self.max = num::max(self.max, id + 1);
351 pub trait IdVisitingOperation {
352 fn visit_id(&self, node_id: NodeId);
355 pub struct IdVisitor<'a, O> {
357 pass_through_items: bool,
358 visited_outermost: bool,
361 impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> {
362 fn visit_generics_helper(&self, generics: &Generics) {
363 for type_parameter in generics.ty_params.iter() {
364 self.operation.visit_id(type_parameter.id)
366 for lifetime in generics.lifetimes.iter() {
367 self.operation.visit_id(lifetime.id)
372 impl<'a, O: IdVisitingOperation> Visitor<()> for IdVisitor<'a, O> {
373 fn visit_mod(&mut self,
378 self.operation.visit_id(node_id);
379 visit::walk_mod(self, module, env)
382 fn visit_view_item(&mut self, view_item: &ViewItem, env: ()) {
383 match view_item.node {
384 ViewItemExternMod(_, _, node_id) => {
385 self.operation.visit_id(node_id)
387 ViewItemUse(ref view_paths) => {
388 for view_path in view_paths.iter() {
389 match view_path.node {
390 ViewPathSimple(_, _, node_id) |
391 ViewPathGlob(_, node_id) => {
392 self.operation.visit_id(node_id)
394 ViewPathList(_, ref paths, node_id) => {
395 self.operation.visit_id(node_id);
396 for path in paths.iter() {
397 self.operation.visit_id(path.node.id)
404 visit::walk_view_item(self, view_item, env)
407 fn visit_foreign_item(&mut self, foreign_item: &ForeignItem, env: ()) {
408 self.operation.visit_id(foreign_item.id);
409 visit::walk_foreign_item(self, foreign_item, env)
412 fn visit_item(&mut self, item: &Item, env: ()) {
413 if !self.pass_through_items {
414 if self.visited_outermost {
417 self.visited_outermost = true
421 self.operation.visit_id(item.id);
423 ItemEnum(ref enum_definition, _) => {
424 for variant in enum_definition.variants.iter() {
425 self.operation.visit_id(variant.node.id)
431 visit::walk_item(self, item, env);
433 self.visited_outermost = false
436 fn visit_local(&mut self, local: &Local, env: ()) {
437 self.operation.visit_id(local.id);
438 visit::walk_local(self, local, env)
441 fn visit_block(&mut self, block: &Block, env: ()) {
442 self.operation.visit_id(block.id);
443 visit::walk_block(self, block, env)
446 fn visit_stmt(&mut self, statement: &Stmt, env: ()) {
447 self.operation.visit_id(ast_util::stmt_id(statement));
448 visit::walk_stmt(self, statement, env)
451 fn visit_pat(&mut self, pattern: &Pat, env: ()) {
452 self.operation.visit_id(pattern.id);
453 visit::walk_pat(self, pattern, env)
457 fn visit_expr(&mut self, expression: &Expr, env: ()) {
459 let optional_callee_id = expression.get_callee_id();
460 for callee_id in optional_callee_id.iter() {
461 self.operation.visit_id(*callee_id)
464 self.operation.visit_id(expression.id);
465 visit::walk_expr(self, expression, env)
468 fn visit_ty(&mut self, typ: &Ty, env: ()) {
469 self.operation.visit_id(typ.id);
471 TyPath(_, _, id) => self.operation.visit_id(id),
474 visit::walk_ty(self, typ, env)
477 fn visit_generics(&mut self, generics: &Generics, env: ()) {
478 self.visit_generics_helper(generics);
479 visit::walk_generics(self, generics, env)
482 fn visit_fn(&mut self,
483 function_kind: &visit::FnKind,
484 function_declaration: &FnDecl,
489 if !self.pass_through_items {
490 match *function_kind {
491 visit::FkMethod(..) if self.visited_outermost => return,
492 visit::FkMethod(..) => self.visited_outermost = true,
497 self.operation.visit_id(node_id);
499 match *function_kind {
500 visit::FkItemFn(_, generics, _, _) |
501 visit::FkMethod(_, generics, _) => {
502 self.visit_generics_helper(generics)
504 visit::FkFnBlock => {}
507 for argument in function_declaration.inputs.iter() {
508 self.operation.visit_id(argument.id)
513 function_declaration,
519 if !self.pass_through_items {
520 match *function_kind {
521 visit::FkMethod(..) => self.visited_outermost = false,
527 fn visit_struct_field(&mut self, struct_field: &StructField, env: ()) {
528 self.operation.visit_id(struct_field.node.id);
529 visit::walk_struct_field(self, struct_field, env)
532 fn visit_struct_def(&mut self,
533 struct_def: &StructDef,
535 generics: &ast::Generics,
538 self.operation.visit_id(id);
539 struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id));
540 visit::walk_struct_def(self, struct_def, ident, generics, id, ());
543 fn visit_trait_method(&mut self, tm: &ast::TraitMethod, _: ()) {
545 ast::Required(ref m) => self.operation.visit_id(m.id),
546 ast::Provided(ref m) => self.operation.visit_id(m.id),
548 visit::walk_trait_method(self, tm, ());
552 pub fn visit_ids_for_inlined_item<O: IdVisitingOperation>(item: &InlinedItem,
554 let mut id_visitor = IdVisitor {
555 operation: operation,
556 pass_through_items: true,
557 visited_outermost: false,
560 visit::walk_inlined_item(&mut id_visitor, item, ());
563 struct IdRangeComputingVisitor {
564 result: Cell<IdRange>,
567 impl IdVisitingOperation for IdRangeComputingVisitor {
568 fn visit_id(&self, id: NodeId) {
569 let mut id_range = self.result.get();
571 self.result.set(id_range)
575 pub fn compute_id_range_for_inlined_item(item: &InlinedItem) -> IdRange {
576 let visitor = IdRangeComputingVisitor {
577 result: Cell::new(IdRange::max())
579 visit_ids_for_inlined_item(item, &visitor);
583 pub fn is_item_impl(item: @ast::Item) -> bool {
585 ItemImpl(..) => true,
590 pub fn walk_pat(pat: &Pat, it: |&Pat| -> bool) -> bool {
596 PatIdent(_, _, Some(p)) => walk_pat(p, it),
597 PatStruct(_, ref fields, _) => {
598 fields.iter().advance(|f| walk_pat(f.pat, |p| it(p)))
600 PatEnum(_, Some(ref s)) | PatTup(ref s) => {
601 s.iter().advance(|&p| walk_pat(p, |p| it(p)))
603 PatUniq(s) | PatRegion(s) => {
606 PatVec(ref before, ref slice, ref after) => {
607 before.iter().advance(|&p| walk_pat(p, |p| it(p))) &&
608 slice.iter().advance(|&p| walk_pat(p, |p| it(p))) &&
609 after.iter().advance(|&p| walk_pat(p, |p| it(p)))
611 PatWild | PatWildMulti | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) |
618 pub trait EachViewItem {
619 fn each_view_item(&self, f: |&ast::ViewItem| -> bool) -> bool;
622 struct EachViewItemData<'a> {
623 callback: 'a |&ast::ViewItem| -> bool,
626 impl<'a> Visitor<()> for EachViewItemData<'a> {
627 fn visit_view_item(&mut self, view_item: &ast::ViewItem, _: ()) {
628 let _ = (self.callback)(view_item);
632 impl EachViewItem for ast::Crate {
633 fn each_view_item(&self, f: |&ast::ViewItem| -> bool) -> bool {
634 let mut visit = EachViewItemData {
637 visit::walk_crate(&mut visit, self, ());
642 pub fn view_path_id(p: &ViewPath) -> NodeId {
644 ViewPathSimple(_, _, id) | ViewPathGlob(_, id)
645 | ViewPathList(_, _, id) => id
649 /// Returns true if the given struct def is tuple-like; i.e. that its fields
651 pub fn struct_def_is_tuple_like(struct_def: &ast::StructDef) -> bool {
652 struct_def.ctor_id.is_some()
655 /// Returns true if the given pattern consists solely of an identifier
656 /// and false otherwise.
657 pub fn pat_is_ident(pat: @ast::Pat) -> bool {
659 ast::PatIdent(..) => true,
666 /// Extend a syntax context with a given mark
667 pub fn new_mark(m:Mrk, tail:SyntaxContext) -> SyntaxContext {
668 new_mark_internal(m,tail,get_sctable())
671 // Extend a syntax context with a given mark and table
672 // FIXME #8215 : currently pub to allow testing
673 pub fn new_mark_internal(m: Mrk, tail: SyntaxContext, table: &SCTable)
676 // FIXME #5074 : can't use more natural style because we're missing
677 // flow-sensitivity. Results in two lookups on a hash table hit.
678 // also applies to new_rename_internal, below.
679 // let try_lookup = table.mark_memo.find(&key);
680 let mut mark_memo = table.mark_memo.borrow_mut();
681 match mark_memo.get().contains_key(&key) {
684 let mut table = table.table.borrow_mut();
685 idx_push(table.get(), Mark(m,tail))
687 mark_memo.get().insert(key,new_idx);
691 match mark_memo.get().find(&key) {
692 None => fail!("internal error: key disappeared 2013042901"),
693 Some(idxptr) => {*idxptr}
699 /// Extend a syntax context with a given rename
700 pub fn new_rename(id:Ident, to:Name, tail:SyntaxContext) -> SyntaxContext {
701 new_rename_internal(id, to, tail, get_sctable())
704 // Extend a syntax context with a given rename and sctable
705 // FIXME #8215 : currently pub to allow testing
706 pub fn new_rename_internal(id: Ident,
711 let key = (tail,id,to);
713 //let try_lookup = table.rename_memo.find(&key);
714 let mut rename_memo = table.rename_memo.borrow_mut();
715 match rename_memo.get().contains_key(&key) {
718 let mut table = table.table.borrow_mut();
719 idx_push(table.get(), Rename(id,to,tail))
721 rename_memo.get().insert(key,new_idx);
725 match rename_memo.get().find(&key) {
726 None => fail!("internal error: key disappeared 2013042902"),
727 Some(idxptr) => {*idxptr}
733 /// Make a fresh syntax context table with EmptyCtxt in slot zero
734 /// and IllegalCtxt in slot one.
735 // FIXME #8215 : currently pub to allow testing
736 pub fn new_sctable_internal() -> SCTable {
738 table: RefCell::new(~[EmptyCtxt,IllegalCtxt]),
739 mark_memo: RefCell::new(HashMap::new()),
740 rename_memo: RefCell::new(HashMap::new()),
744 // fetch the SCTable from TLS, create one if it doesn't yet exist.
745 pub fn get_sctable() -> @SCTable {
746 local_data_key!(sctable_key: @@SCTable)
747 match local_data::get(sctable_key, |k| k.map(|k| *k)) {
749 let new_table = @@new_sctable_internal();
750 local_data::set(sctable_key,new_table);
757 /// print out an SCTable for debugging
758 pub fn display_sctable(table : &SCTable) {
760 let table = table.table.borrow();
761 for (idx,val) in table.get().iter().enumerate() {
762 error!("{:4u} : {:?}",idx,val);
767 /// Add a value to the end of a vec, return its index
768 fn idx_push<T>(vec: &mut ~[T], val: T) -> u32 {
770 (vec.len() - 1) as u32
773 /// Resolve a syntax object to a name, per MTWT.
774 pub fn mtwt_resolve(id : Ident) -> Name {
775 let resolve_table = get_resolve_table();
776 let mut resolve_table = resolve_table.borrow_mut();
777 resolve_internal(id, get_sctable(), resolve_table.get())
780 // FIXME #8215: must be pub for testing
781 pub type ResolveTable = HashMap<(Name,SyntaxContext),Name>;
783 // okay, I admit, putting this in TLS is not so nice:
784 // fetch the SCTable from TLS, create one if it doesn't yet exist.
785 pub fn get_resolve_table() -> @RefCell<ResolveTable> {
786 local_data_key!(resolve_table_key: @@RefCell<ResolveTable>)
787 match local_data::get(resolve_table_key, |k| k.map(|k| *k)) {
789 let new_table = @@RefCell::new(HashMap::new());
790 local_data::set(resolve_table_key, new_table);
797 // Resolve a syntax object to a name, per MTWT.
798 // adding memoization to possibly resolve 500+ seconds in resolve for librustc (!)
799 // FIXME #8215 : currently pub to allow testing
800 pub fn resolve_internal(id : Ident,
802 resolve_table : &mut ResolveTable) -> Name {
803 let key = (id.name,id.ctxt);
804 match resolve_table.contains_key(&key) {
808 let table = table.table.borrow();
812 EmptyCtxt => id.name,
813 // ignore marks here:
815 resolve_internal(Ident{name:id.name, ctxt: subctxt},table,resolve_table),
816 // do the rename if necessary:
817 Rename(Ident{name,ctxt},toname,subctxt) => {
819 resolve_internal(Ident{name:name,ctxt:ctxt},table,resolve_table);
821 resolve_internal(Ident{name:id.name,ctxt:subctxt},table,resolve_table);
822 if (resolvedthis == resolvedfrom)
823 && (marksof(ctxt,resolvedthis,table)
824 == marksof(subctxt,resolvedthis,table)) {
830 IllegalCtxt() => fail!("expected resolvable context, got IllegalCtxt")
833 resolve_table.insert(key,resolved);
837 // it's guaranteed to be there, because we just checked that it was
838 // there and we never remove anything from the table:
839 *(resolve_table.find(&key).unwrap())
844 /// Compute the marks associated with a syntax context.
845 pub fn mtwt_marksof(ctxt: SyntaxContext, stopname: Name) -> ~[Mrk] {
846 marksof(ctxt, stopname, get_sctable())
849 // the internal function for computing marks
850 // it's not clear to me whether it's better to use a [] mutable
851 // vector or a cons-list for this.
852 pub fn marksof(ctxt: SyntaxContext, stopname: Name, table: &SCTable) -> ~[Mrk] {
853 let mut result = ~[];
854 let mut loopvar = ctxt;
857 let table = table.table.borrow();
865 xorPush(&mut result, mark);
868 Rename(_,name,tl) => {
869 // see MTWT for details on the purpose of the stopname.
870 // short version: it prevents duplication of effort.
871 if name == stopname {
877 IllegalCtxt => fail!("expected resolvable context, got IllegalCtxt")
882 /// Return the outer mark for a context with a mark at the outside.
883 /// FAILS when outside is not a mark.
884 pub fn mtwt_outer_mark(ctxt: SyntaxContext) -> Mrk {
885 let sctable = get_sctable();
886 let table = sctable.table.borrow();
887 match table.get()[ctxt] {
888 ast::Mark(mrk,_) => mrk,
889 _ => fail!("can't retrieve outer mark when outside is not a mark")
893 /// Push a name... unless it matches the one on top, in which
894 /// case pop and discard (so two of the same marks cancel)
895 pub fn xorPush(marks: &mut ~[Mrk], mark: Mrk) {
896 if (marks.len() > 0) && (getLast(marks) == mark) {
897 marks.pop().unwrap();
903 // get the last element of a mutable array.
904 // FIXME #4903: , must be a separate procedure for now.
905 pub fn getLast(arr: &~[Mrk]) -> Mrk {
909 // are two paths equal when compared unhygienically?
910 // since I'm using this to replace ==, it seems appropriate
911 // to compare the span, global, etc. fields as well.
912 pub fn path_name_eq(a : &ast::Path, b : &ast::Path) -> bool {
914 && (a.global == b.global)
915 && (segments_name_eq(a.segments, b.segments))
918 // are two arrays of segments equal when compared unhygienically?
919 pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> bool {
920 if a.len() != b.len() {
923 for (idx,seg) in a.iter().enumerate() {
924 if (seg.identifier.name != b[idx].identifier.name)
925 // FIXME #7743: ident -> name problems in lifetime comparison?
926 || (seg.lifetimes != b[idx].lifetimes)
927 // can types contain idents?
928 || (seg.types != b[idx].types) {
936 // Returns true if this literal is a string and false otherwise.
937 pub fn lit_is_str(lit: @Lit) -> bool {
950 use std::hashmap::HashMap;
952 fn ident_to_segment(id : &Ident) -> PathSegment {
953 PathSegment {identifier:id.clone(),
954 lifetimes: opt_vec::Empty,
955 types: opt_vec::Empty}
958 #[test] fn idents_name_eq_test() {
959 assert!(segments_name_eq([Ident{name:3,ctxt:4},
960 Ident{name:78,ctxt:82}].map(ident_to_segment),
961 [Ident{name:3,ctxt:104},
962 Ident{name:78,ctxt:182}].map(ident_to_segment)));
963 assert!(!segments_name_eq([Ident{name:3,ctxt:4},
964 Ident{name:78,ctxt:82}].map(ident_to_segment),
965 [Ident{name:3,ctxt:104},
966 Ident{name:77,ctxt:182}].map(ident_to_segment)));
969 #[test] fn xorpush_test () {
972 assert_eq!(s.clone(), ~[14]);
974 assert_eq!(s.clone(), ~[]);
976 assert_eq!(s.clone(), ~[14]);
978 assert_eq!(s.clone(), ~[14, 15]);
980 assert_eq!(s.clone(), ~[14, 15, 16]);
982 assert_eq!(s.clone(), ~[14, 15]);
984 assert_eq!(s.clone(), ~[14]);
987 fn id(n: Name, s: SyntaxContext) -> Ident {
988 Ident {name: n, ctxt: s}
991 // because of the SCTable, I now need a tidy way of
992 // creating syntax objects. Sigh.
993 #[deriving(Clone, Eq)]
999 // unfold a vector of TestSC values into a SCTable,
1000 // returning the resulting index
1001 fn unfold_test_sc(tscs : ~[TestSC], tail: SyntaxContext, table: &SCTable)
1003 tscs.rev_iter().fold(tail, |tail : SyntaxContext, tsc : &TestSC|
1005 M(mrk) => new_mark_internal(mrk,tail,table),
1006 R(ident,name) => new_rename_internal(ident,name,tail,table)}})
1009 // gather a SyntaxContext back into a vector of TestSCs
1010 fn refold_test_sc(mut sc: SyntaxContext, table : &SCTable) -> ~[TestSC] {
1011 let mut result = ~[];
1013 let table = table.table.borrow();
1014 match table.get()[sc] {
1015 EmptyCtxt => {return result;},
1017 result.push(M(mrk));
1021 Rename(id,name,tail) => {
1022 result.push(R(id,name));
1026 IllegalCtxt => fail!("expected resolvable context, got IllegalCtxt")
1031 #[test] fn test_unfold_refold(){
1032 let mut t = new_sctable_internal();
1034 let test_sc = ~[M(3),R(id(101,0),14),M(9)];
1035 assert_eq!(unfold_test_sc(test_sc.clone(),EMPTY_CTXT,&mut t),4);
1037 let table = t.table.borrow();
1038 assert_eq!(table.get()[2],Mark(9,0));
1039 assert_eq!(table.get()[3],Rename(id(101,0),14,2));
1040 assert_eq!(table.get()[4],Mark(3,3));
1042 assert_eq!(refold_test_sc(4,&t),test_sc);
1045 // extend a syntax context with a sequence of marks given
1046 // in a vector. v[0] will be the outermost mark.
1047 fn unfold_marks(mrks: ~[Mrk], tail: SyntaxContext, table: &SCTable)
1049 mrks.rev_iter().fold(tail, |tail:SyntaxContext, mrk:&Mrk|
1050 {new_mark_internal(*mrk,tail,table)})
1053 #[test] fn unfold_marks_test() {
1054 let mut t = new_sctable_internal();
1056 assert_eq!(unfold_marks(~[3,7],EMPTY_CTXT,&mut t),3);
1058 let table = t.table.borrow();
1059 assert_eq!(table.get()[2],Mark(7,0));
1060 assert_eq!(table.get()[3],Mark(3,2));
1064 #[test] fn test_marksof () {
1067 let mut t = new_sctable_internal();
1068 assert_eq!(marksof (EMPTY_CTXT,stopname,&t),~[]);
1069 // FIXME #5074: ANF'd to dodge nested calls
1070 { let ans = unfold_marks(~[4,98],EMPTY_CTXT,&mut t);
1071 assert_eq! (marksof (ans,stopname,&t),~[4,98]);}
1072 // does xoring work?
1073 { let ans = unfold_marks(~[5,5,16],EMPTY_CTXT,&mut t);
1074 assert_eq! (marksof (ans,stopname,&t), ~[16]);}
1075 // does nested xoring work?
1076 { let ans = unfold_marks(~[5,10,10,5,16],EMPTY_CTXT,&mut t);
1077 assert_eq! (marksof (ans, stopname,&t), ~[16]);}
1078 // rename where stop doesn't match:
1079 { let chain = ~[M(9),
1081 new_mark_internal (4, EMPTY_CTXT,&mut t)),
1084 let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t);
1085 assert_eq! (marksof (ans, stopname, &t), ~[9,14]);}
1086 // rename where stop does match
1087 { let name1sc = new_mark_internal(4, EMPTY_CTXT, &mut t);
1089 R(id(name1, name1sc),
1092 let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t);
1093 assert_eq! (marksof (ans, stopname, &t), ~[9]); }
1097 #[test] fn resolve_tests () {
1099 let mut t = new_sctable_internal();
1100 let mut rt = HashMap::new();
1102 assert_eq!(resolve_internal(id(a,EMPTY_CTXT),&mut t, &mut rt),a);
1103 // - simple ignored marks
1104 { let sc = unfold_marks(~[1,2,3],EMPTY_CTXT,&mut t);
1105 assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),a);}
1106 // - orthogonal rename where names don't match
1107 { let sc = unfold_test_sc(~[R(id(50,EMPTY_CTXT),51),M(12)],EMPTY_CTXT,&mut t);
1108 assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),a);}
1109 // - rename where names do match, but marks don't
1110 { let sc1 = new_mark_internal(1,EMPTY_CTXT,&mut t);
1111 let sc = unfold_test_sc(~[R(id(a,sc1),50),
1115 assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), a);}
1116 // - rename where names and marks match
1117 { let sc1 = unfold_test_sc(~[M(1),M(2)],EMPTY_CTXT,&mut t);
1118 let sc = unfold_test_sc(~[R(id(a,sc1),50),M(1),M(2)],EMPTY_CTXT,&mut t);
1119 assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 50); }
1120 // - rename where names and marks match by literal sharing
1121 { let sc1 = unfold_test_sc(~[M(1),M(2)],EMPTY_CTXT,&mut t);
1122 let sc = unfold_test_sc(~[R(id(a,sc1),50)],sc1,&mut t);
1123 assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 50); }
1124 // - two renames of the same var.. can only happen if you use
1125 // local-expand to prevent the inner binding from being renamed
1126 // during the rename-pass caused by the first:
1127 println!("about to run bad test");
1128 { let sc = unfold_test_sc(~[R(id(a,EMPTY_CTXT),50),
1129 R(id(a,EMPTY_CTXT),51)],
1131 assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 51); }
1132 // the simplest double-rename:
1133 { let a_to_a50 = new_rename_internal(id(a,EMPTY_CTXT),50,EMPTY_CTXT,&mut t);
1134 let a50_to_a51 = new_rename_internal(id(a,a_to_a50),51,a_to_a50,&mut t);
1135 assert_eq!(resolve_internal(id(a,a50_to_a51),&mut t, &mut rt),51);
1136 // mark on the outside doesn't stop rename:
1137 let sc = new_mark_internal(9,a50_to_a51,&mut t);
1138 assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),51);
1139 // but mark on the inside does:
1140 let a50_to_a51_b = unfold_test_sc(~[R(id(a,a_to_a50),51),
1144 assert_eq!(resolve_internal(id(a,a50_to_a51_b),&mut t, &mut rt),50);}
1147 #[test] fn mtwt_resolve_test(){
1149 assert_eq!(mtwt_resolve(id(a,EMPTY_CTXT)),a);
1153 #[test] fn hashing_tests () {
1154 let mut t = new_sctable_internal();
1155 assert_eq!(new_mark_internal(12,EMPTY_CTXT,&mut t),2);
1156 assert_eq!(new_mark_internal(13,EMPTY_CTXT,&mut t),3);
1157 // using the same one again should result in the same index:
1158 assert_eq!(new_mark_internal(12,EMPTY_CTXT,&mut t),2);
1159 // I'm assuming that the rename table will behave the same....
1162 #[test] fn resolve_table_hashing_tests() {
1163 let mut t = new_sctable_internal();
1164 let mut rt = HashMap::new();
1165 assert_eq!(rt.len(),0);
1166 resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt);
1167 assert_eq!(rt.len(),1);
1168 resolve_internal(id(39,EMPTY_CTXT),&mut t, &mut rt);
1169 assert_eq!(rt.len(),2);
1170 resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt);
1171 assert_eq!(rt.len(),2);