1 // Copyright 2012-2014 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.
16 use owned_slice
::OwnedSlice
;
26 pub fn path_name_i(idents
: &[Ident
]) -> String
{
27 // FIXME: Bad copies (#2543 -- same for everything else that says "bad")
28 idents
.iter().map(|i
| {
29 token
::get_ident(*i
).to_string()
30 }).collect
::<Vec
<String
>>().connect("::")
33 pub fn local_def(id
: NodeId
) -> DefId
{
34 ast
::DefId { krate: LOCAL_CRATE, node: id }
37 pub fn is_local(did
: ast
::DefId
) -> bool { did.krate == LOCAL_CRATE }
39 pub fn stmt_id(s
: &Stmt
) -> NodeId
{
41 StmtDecl(_
, id
) => id
,
42 StmtExpr(_
, id
) => id
,
43 StmtSemi(_
, id
) => id
,
44 StmtMac(..) => panic
!("attempted to analyze unexpanded stmt")
48 pub fn binop_to_string(op
: BinOp_
) -> &'
static str {
71 pub fn lazy_binop(b
: BinOp_
) -> bool
{
79 pub fn is_shift_binop(b
: BinOp_
) -> bool
{
87 pub fn is_comparison_binop(b
: BinOp_
) -> bool
{
89 BiEq
| BiLt
| BiLe
| BiNe
| BiGt
| BiGe
=>
91 BiAnd
| BiOr
| BiAdd
| BiSub
| BiMul
| BiDiv
| BiRem
|
92 BiBitXor
| BiBitAnd
| BiBitOr
| BiShl
| BiShr
=>
97 /// Returns `true` if the binary operator takes its arguments by value
98 pub fn is_by_value_binop(b
: BinOp_
) -> bool
{
99 !is_comparison_binop(b
)
102 /// Returns `true` if the unary operator takes its argument by value
103 pub fn is_by_value_unop(u
: UnOp
) -> bool
{
105 UnNeg
| UnNot
=> true,
110 pub fn unop_to_string(op
: UnOp
) -> &'
static str {
119 pub fn is_path(e
: P
<Expr
>) -> bool
{
120 match e
.node { ExprPath(..) => true, _ => false }
123 /// Get a string representation of a signed int type, with its value.
124 /// We want to avoid "45int" and "-3int" in favor of "45" and "-3"
125 pub fn int_ty_to_string(t
: IntTy
, val
: Option
<i64>) -> String
{
135 // cast to a u64 so we can correctly print INT64_MIN. All integral types
136 // are parsed as u64, so we wouldn't want to print an extra negative
138 Some(n
) => format
!("{}{}", n
as u64, s
),
139 None
=> s
.to_string()
143 pub fn int_ty_max(t
: IntTy
) -> u64 {
147 TyIs
| TyI32
=> 0x80000000, // actually ni about TyIs
148 TyI64
=> 0x8000000000000000
152 /// Get a string representation of an unsigned int type, with its value.
153 /// We want to avoid "42u" in favor of "42us". "42uint" is right out.
154 pub fn uint_ty_to_string(t
: UintTy
, val
: Option
<u64>) -> String
{
164 Some(n
) => format
!("{}{}", n
, s
),
165 None
=> s
.to_string()
169 pub fn uint_ty_max(t
: UintTy
) -> u64 {
173 TyUs
| TyU32
=> 0xffffffff, // actually ni about TyUs
174 TyU64
=> 0xffffffffffffffff
178 pub fn float_ty_to_string(t
: FloatTy
) -> String
{
180 TyF32
=> "f32".to_string(),
181 TyF64
=> "f64".to_string(),
185 // convert a span and an identifier to the corresponding
187 pub fn ident_to_path(s
: Span
, identifier
: Ident
) -> Path
{
193 identifier
: identifier
,
194 parameters
: ast
::AngleBracketedParameters(ast
::AngleBracketedParameterData
{
195 lifetimes
: Vec
::new(),
196 types
: OwnedSlice
::empty(),
197 bindings
: OwnedSlice
::empty(),
204 // If path is a single segment ident path, return that ident. Otherwise, return
206 pub fn path_to_ident(path
: &Path
) -> Option
<Ident
> {
207 if path
.segments
.len() != 1 {
211 let segment
= &path
.segments
[0];
212 if !segment
.parameters
.is_empty() {
216 Some(segment
.identifier
)
219 pub fn ident_to_pat(id
: NodeId
, s
: Span
, i
: Ident
) -> P
<Pat
> {
222 node
: PatIdent(BindByValue(MutImmutable
), codemap
::Spanned{span:s, node:i}
, None
),
227 pub fn name_to_dummy_lifetime(name
: Name
) -> Lifetime
{
228 Lifetime
{ id
: DUMMY_NODE_ID
,
229 span
: codemap
::DUMMY_SP
,
233 /// Generate a "pretty" name for an `impl` from its type and trait.
234 /// This is designed so that symbols of `impl`'d methods give some
235 /// hint of where they came from, (previously they would all just be
236 /// listed as `__extensions__::method_name::hash`, with no indication
238 pub fn impl_pretty_name(trait_ref
: &Option
<TraitRef
>, ty
: Option
<&Ty
>) -> Ident
{
239 let mut pretty
= match ty
{
240 Some(t
) => pprust
::ty_to_string(t
),
241 None
=> String
::from("..")
245 Some(ref trait_ref
) => {
247 pretty
.push_str(&pprust
::path_to_string(&trait_ref
.path
));
251 token
::gensym_ident(&pretty
[..])
254 pub fn struct_field_visibility(field
: ast
::StructField
) -> Visibility
{
255 match field
.node
.kind
{
256 ast
::NamedField(_
, v
) | ast
::UnnamedField(v
) => v
260 /// Maps a binary operator to its precedence
261 pub fn operator_prec(op
: ast
::BinOp_
) -> usize {
263 // 'as' sits here with 12
264 BiMul
| BiDiv
| BiRem
=> 11,
270 BiLt
| BiLe
| BiGe
| BiGt
| BiEq
| BiNe
=> 3,
276 /// Precedence of the `as` operator, which is a binary operator
277 /// not appearing in the prior table.
278 pub const AS_PREC
: usize = 12;
280 pub fn empty_generics() -> Generics
{
282 lifetimes
: Vec
::new(),
283 ty_params
: OwnedSlice
::empty(),
284 where_clause
: WhereClause
{
286 predicates
: Vec
::new(),
291 // ______________________________________________________________________
292 // Enumerating the IDs which appear in an AST
294 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
301 pub fn max() -> IdRange
{
308 pub fn empty(&self) -> bool
{
312 pub fn add(&mut self, id
: NodeId
) {
313 self.min
= cmp
::min(self.min
, id
);
314 self.max
= cmp
::max(self.max
, id
+ 1);
318 pub trait IdVisitingOperation
{
319 fn visit_id(&mut self, node_id
: NodeId
);
322 /// A visitor that applies its operation to all of the node IDs
323 /// in a visitable thing.
325 pub struct IdVisitor
<'a
, O
:'a
> {
326 pub operation
: &'a
mut O
,
327 pub pass_through_items
: bool
,
328 pub visited_outermost
: bool
,
331 impl<'a
, O
: IdVisitingOperation
> IdVisitor
<'a
, O
> {
332 fn visit_generics_helper(&mut self, generics
: &Generics
) {
333 for type_parameter
in &*generics
.ty_params
{
334 self.operation
.visit_id(type_parameter
.id
)
336 for lifetime
in &generics
.lifetimes
{
337 self.operation
.visit_id(lifetime
.lifetime
.id
)
342 impl<'a
, 'v
, O
: IdVisitingOperation
> Visitor
<'v
> for IdVisitor
<'a
, O
> {
343 fn visit_mod(&mut self,
347 self.operation
.visit_id(node_id
);
348 visit
::walk_mod(self, module
)
351 fn visit_foreign_item(&mut self, foreign_item
: &ForeignItem
) {
352 self.operation
.visit_id(foreign_item
.id
);
353 visit
::walk_foreign_item(self, foreign_item
)
356 fn visit_item(&mut self, item
: &Item
) {
357 if !self.pass_through_items
{
358 if self.visited_outermost
{
361 self.visited_outermost
= true
365 self.operation
.visit_id(item
.id
);
367 ItemUse(ref view_path
) => {
368 match view_path
.node
{
369 ViewPathSimple(_
, _
) |
370 ViewPathGlob(_
) => {}
371 ViewPathList(_
, ref paths
) => {
373 self.operation
.visit_id(path
.node
.id())
378 ItemEnum(ref enum_definition
, _
) => {
379 for variant
in &enum_definition
.variants
{
380 self.operation
.visit_id(variant
.node
.id
)
386 visit
::walk_item(self, item
);
388 self.visited_outermost
= false
391 fn visit_local(&mut self, local
: &Local
) {
392 self.operation
.visit_id(local
.id
);
393 visit
::walk_local(self, local
)
396 fn visit_block(&mut self, block
: &Block
) {
397 self.operation
.visit_id(block
.id
);
398 visit
::walk_block(self, block
)
401 fn visit_stmt(&mut self, statement
: &Stmt
) {
402 self.operation
.visit_id(ast_util
::stmt_id(statement
));
403 visit
::walk_stmt(self, statement
)
406 fn visit_pat(&mut self, pattern
: &Pat
) {
407 self.operation
.visit_id(pattern
.id
);
408 visit
::walk_pat(self, pattern
)
411 fn visit_expr(&mut self, expression
: &Expr
) {
412 self.operation
.visit_id(expression
.id
);
413 visit
::walk_expr(self, expression
)
416 fn visit_ty(&mut self, typ
: &Ty
) {
417 self.operation
.visit_id(typ
.id
);
418 visit
::walk_ty(self, typ
)
421 fn visit_generics(&mut self, generics
: &Generics
) {
422 self.visit_generics_helper(generics
);
423 visit
::walk_generics(self, generics
)
426 fn visit_fn(&mut self,
427 function_kind
: visit
::FnKind
<'v
>,
428 function_declaration
: &'v FnDecl
,
432 if !self.pass_through_items
{
433 match function_kind
{
434 visit
::FkMethod(..) if self.visited_outermost
=> return,
435 visit
::FkMethod(..) => self.visited_outermost
= true,
440 self.operation
.visit_id(node_id
);
442 match function_kind
{
443 visit
::FkItemFn(_
, generics
, _
, _
, _
) => {
444 self.visit_generics_helper(generics
)
446 visit
::FkMethod(_
, sig
, _
) => {
447 self.visit_generics_helper(&sig
.generics
)
449 visit
::FkFnBlock
=> {}
452 for argument
in &function_declaration
.inputs
{
453 self.operation
.visit_id(argument
.id
)
458 function_declaration
,
462 if !self.pass_through_items
{
463 if let visit
::FkMethod(..) = function_kind
{
464 self.visited_outermost
= false;
469 fn visit_struct_field(&mut self, struct_field
: &StructField
) {
470 self.operation
.visit_id(struct_field
.node
.id
);
471 visit
::walk_struct_field(self, struct_field
)
474 fn visit_struct_def(&mut self,
475 struct_def
: &StructDef
,
479 self.operation
.visit_id(id
);
480 struct_def
.ctor_id
.map(|ctor_id
| self.operation
.visit_id(ctor_id
));
481 visit
::walk_struct_def(self, struct_def
);
484 fn visit_trait_item(&mut self, ti
: &ast
::TraitItem
) {
485 self.operation
.visit_id(ti
.id
);
486 visit
::walk_trait_item(self, ti
);
489 fn visit_impl_item(&mut self, ii
: &ast
::ImplItem
) {
490 self.operation
.visit_id(ii
.id
);
491 visit
::walk_impl_item(self, ii
);
494 fn visit_lifetime_ref(&mut self, lifetime
: &Lifetime
) {
495 self.operation
.visit_id(lifetime
.id
);
498 fn visit_lifetime_def(&mut self, def
: &LifetimeDef
) {
499 self.visit_lifetime_ref(&def
.lifetime
);
502 fn visit_trait_ref(&mut self, trait_ref
: &TraitRef
) {
503 self.operation
.visit_id(trait_ref
.ref_id
);
504 visit
::walk_trait_ref(self, trait_ref
);
508 pub fn visit_ids_for_inlined_item
<O
: IdVisitingOperation
>(item
: &InlinedItem
,
510 let mut id_visitor
= IdVisitor
{
511 operation
: operation
,
512 pass_through_items
: true,
513 visited_outermost
: false,
516 visit
::walk_inlined_item(&mut id_visitor
, item
);
519 struct IdRangeComputingVisitor
{
523 impl IdVisitingOperation
for IdRangeComputingVisitor
{
524 fn visit_id(&mut self, id
: NodeId
) {
529 pub fn compute_id_range_for_inlined_item(item
: &InlinedItem
) -> IdRange
{
530 let mut visitor
= IdRangeComputingVisitor
{
531 result
: IdRange
::max()
533 visit_ids_for_inlined_item(item
, &mut visitor
);
537 /// Computes the id range for a single fn body, ignoring nested items.
538 pub fn compute_id_range_for_fn_body(fk
: visit
::FnKind
,
545 let mut visitor
= IdRangeComputingVisitor
{
546 result
: IdRange
::max()
548 let mut id_visitor
= IdVisitor
{
549 operation
: &mut visitor
,
550 pass_through_items
: false,
551 visited_outermost
: false,
553 id_visitor
.visit_fn(fk
, decl
, body
, sp
, id
);
554 id_visitor
.operation
.result
557 pub fn walk_pat
<F
>(pat
: &Pat
, mut it
: F
) -> bool
where F
: FnMut(&Pat
) -> bool
{
558 // FIXME(#19596) this is a workaround, but there should be a better way
559 fn walk_pat_
<G
>(pat
: &Pat
, it
: &mut G
) -> bool
where G
: FnMut(&Pat
) -> bool
{
565 PatIdent(_
, _
, Some(ref p
)) => walk_pat_(&**p
, it
),
566 PatStruct(_
, ref fields
, _
) => {
567 fields
.iter().all(|field
| walk_pat_(&*field
.node
.pat
, it
))
569 PatEnum(_
, Some(ref s
)) | PatTup(ref s
) => {
570 s
.iter().all(|p
| walk_pat_(&**p
, it
))
572 PatBox(ref s
) | PatRegion(ref s
, _
) => {
575 PatVec(ref before
, ref slice
, ref after
) => {
576 before
.iter().all(|p
| walk_pat_(&**p
, it
)) &&
577 slice
.iter().all(|p
| walk_pat_(&**p
, it
)) &&
578 after
.iter().all(|p
| walk_pat_(&**p
, it
))
580 PatMac(_
) => panic
!("attempted to analyze unexpanded pattern"),
581 PatWild(_
) | PatLit(_
) | PatRange(_
, _
) | PatIdent(_
, _
, _
) |
582 PatEnum(_
, _
) | PatQPath(_
, _
) => {
588 walk_pat_(pat
, &mut it
)
591 /// Returns true if the given struct def is tuple-like; i.e. that its fields
593 pub fn struct_def_is_tuple_like(struct_def
: &ast
::StructDef
) -> bool
{
594 struct_def
.ctor_id
.is_some()
597 /// Returns true if the given pattern consists solely of an identifier
598 /// and false otherwise.
599 pub fn pat_is_ident(pat
: P
<ast
::Pat
>) -> bool
{
601 ast
::PatIdent(..) => true,
606 // are two paths equal when compared unhygienically?
607 // since I'm using this to replace ==, it seems appropriate
608 // to compare the span, global, etc. fields as well.
609 pub fn path_name_eq(a
: &ast
::Path
, b
: &ast
::Path
) -> bool
{
611 && (a
.global
== b
.global
)
612 && (segments_name_eq(&a
.segments
[..], &b
.segments
[..]))
615 // are two arrays of segments equal when compared unhygienically?
616 pub fn segments_name_eq(a
: &[ast
::PathSegment
], b
: &[ast
::PathSegment
]) -> bool
{
617 a
.len() == b
.len() &&
618 a
.iter().zip(b
.iter()).all(|(s
, t
)| {
619 s
.identifier
.name
== t
.identifier
.name
&&
620 // FIXME #7743: ident -> name problems in lifetime comparison?
621 // can types contain idents?
622 s
.parameters
== t
.parameters
626 /// Returns true if this literal is a string and false otherwise.
627 pub fn lit_is_str(lit
: &Lit
) -> bool
{
639 fn ident_to_segment(id
: &Ident
) -> PathSegment
{
640 PathSegment
{identifier
: id
.clone(),
641 parameters
: PathParameters
::none()}
644 #[test] fn idents_name_eq_test() {
645 assert
!(segments_name_eq(
646 &[Ident{name:Name(3),ctxt:4}
, Ident{name:Name(78),ctxt:82}
]
647 .iter().map(ident_to_segment
).collect
::<Vec
<PathSegment
>>(),
648 &[Ident{name:Name(3),ctxt:104}
, Ident{name:Name(78),ctxt:182}
]
649 .iter().map(ident_to_segment
).collect
::<Vec
<PathSegment
>>()));
650 assert
!(!segments_name_eq(
651 &[Ident{name:Name(3),ctxt:4}
, Ident{name:Name(78),ctxt:82}
]
652 .iter().map(ident_to_segment
).collect
::<Vec
<PathSegment
>>(),
653 &[Ident{name:Name(3),ctxt:104}
, Ident{name:Name(77),ctxt:182}
]
654 .iter().map(ident_to_segment
).collect
::<Vec
<PathSegment
>>()));