1 // Copyright 2015 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.
11 use syntax::ast::{self, Mutability};
12 use syntax::print::pprust;
13 use syntax::codemap::{self, Span, BytePos};
16 use lists::{format_item_list, itemize_list, format_fn_args};
17 use rewrite::{Rewrite, RewriteContext};
18 use utils::{extra_offset, span_after, format_mutability, wrap_str};
19 use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple};
21 // Does not wrap on simple segments.
22 pub fn rewrite_path(context: &RewriteContext,
24 qself: Option<&ast::QSelf>,
29 let skip_count = qself.map(|x| x.position).unwrap_or(0);
31 let mut result = if path.global {
37 let mut span_lo = path.span.lo;
39 if let Some(ref qself) = qself {
41 let fmt_ty = try_opt!(qself.ty.rewrite(context, width, offset));
42 result.push_str(&fmt_ty);
45 result.push_str(" as ");
47 let extra_offset = extra_offset(&result, offset);
49 let budget = try_opt!(width.checked_sub(extra_offset + 3));
51 result = try_opt!(rewrite_path_segments(expr_context,
53 path.segments.iter().take(skip_count),
58 offset + extra_offset));
61 result.push_str(">::");
62 span_lo = qself.ty.span.hi + BytePos(1);
65 let extra_offset = extra_offset(&result, offset);
66 let budget = try_opt!(width.checked_sub(extra_offset));
67 rewrite_path_segments(expr_context,
69 path.segments.iter().skip(skip_count),
74 offset + extra_offset)
77 fn rewrite_path_segments<'a, I>(expr_context: bool,
82 context: &RewriteContext,
86 where I: Iterator<Item = &'a ast::PathSegment>
94 buffer.push_str("::");
97 let extra_offset = extra_offset(&buffer, offset);
98 let remaining_width = try_opt!(width.checked_sub(extra_offset));
99 let new_offset = offset + extra_offset;
100 let segment_string = try_opt!(rewrite_segment(expr_context,
108 buffer.push_str(&segment_string);
115 enum SegmentParam<'a> {
116 LifeTime(&'a ast::Lifetime),
118 Binding(&'a ast::TypeBinding),
121 impl<'a> SegmentParam<'a> {
122 fn get_span(&self) -> Span {
124 SegmentParam::LifeTime(ref lt) => lt.span,
125 SegmentParam::Type(ref ty) => ty.span,
126 SegmentParam::Binding(ref binding) => binding.span,
131 impl<'a> Rewrite for SegmentParam<'a> {
132 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
134 SegmentParam::LifeTime(ref lt) => {
135 wrap_str(pprust::lifetime_to_string(lt),
136 context.config.max_width,
140 SegmentParam::Type(ref ty) => ty.rewrite(context, width, offset),
141 SegmentParam::Binding(ref binding) => {
142 let mut result = format!("{} = ", binding.ident);
143 let budget = try_opt!(width.checked_sub(result.len()));
144 let rewrite = try_opt!(binding.ty.rewrite(context, budget, offset + result.len()));
145 result.push_str(&rewrite);
152 // Formats a path segment. There are some hacks involved to correctly determine
153 // the segment's associated span since it's not part of the AST.
155 // The span_lo is assumed to be greater than the end of any previous segment's
156 // parameters and lesser or equal than the start of current segment.
158 // span_hi is assumed equal to the end of the entire path.
160 // When the segment contains a positive number of parameters, we update span_lo
161 // so that invariants described above will hold for the next segment.
162 fn rewrite_segment(expr_context: bool,
163 segment: &ast::PathSegment,
164 span_lo: &mut BytePos,
166 context: &RewriteContext,
170 let ident_len = segment.identifier.to_string().len();
171 let width = try_opt!(width.checked_sub(ident_len));
172 let offset = offset + ident_len;
174 let params = match segment.parameters {
175 ast::PathParameters::AngleBracketedParameters(ref data) if !data.lifetimes.is_empty() ||
176 !data.types.is_empty() ||
177 !data.bindings.is_empty() => {
178 let param_list = data.lifetimes
180 .map(SegmentParam::LifeTime)
181 .chain(data.types.iter().map(|x| SegmentParam::Type(&*x)))
182 .chain(data.bindings.iter().map(|x| SegmentParam::Binding(&*x)))
183 .collect::<Vec<_>>();
185 let next_span_lo = param_list.last().unwrap().get_span().hi + BytePos(1);
186 let list_lo = span_after(codemap::mk_sp(*span_lo, span_hi), "<", context.codemap);
187 let separator = if expr_context {
194 let extra_offset = 1 + separator.len();
196 let list_width = try_opt!(width.checked_sub(extra_offset + 1));
198 let items = itemize_list(context.codemap,
199 param_list.into_iter(),
201 |param| param.get_span().lo,
202 |param| param.get_span().hi,
203 |seg| seg.rewrite(context, list_width, offset + extra_offset),
206 let list_str = try_opt!(format_item_list(items,
208 offset + extra_offset,
211 // Update position of last bracket.
212 *span_lo = next_span_lo;
214 format!("{}<{}>", separator, list_str)
216 ast::PathParameters::ParenthesizedParameters(ref data) => {
218 let budget = try_opt!(width.checked_sub(2));
220 let offset = offset + 1;
221 let list_lo = span_after(data.span, "(", context.codemap);
222 let items = itemize_list(context.codemap,
227 |ty| ty.rewrite(context, budget, offset),
230 println!("got here");
232 let list_str = try_opt!(format_fn_args(items, budget, offset, context.config));
234 println!("got here 2");
235 let output = match data.output {
237 let budget = try_opt!(width.checked_sub(4));
238 let type_str = try_opt!(ty.rewrite(context, budget, offset + 4));
239 format!(" -> {}", type_str)
241 None => String::new(),
244 println!("got here 3");
246 let infix = if output.len() + list_str.len() > width {
247 format!("\n{}", (offset - 1).to_string(context.config))
251 println!("({}){}{}", &list_str, &infix, &output);
253 format!("({}){}{}", list_str, infix, output)
258 Some(format!("{}{}", segment.identifier, params))
261 impl Rewrite for ast::WherePredicate {
262 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
264 let result = match *self {
265 ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { ref bound_lifetimes,
269 let type_str = try_opt!(bounded_ty.rewrite(context, width, offset));
271 if !bound_lifetimes.is_empty() {
272 let lifetime_str = try_opt!(bound_lifetimes.iter()
278 .collect::<Option<Vec<_>>>())
280 // 8 = "for<> : ".len()
281 let used_width = lifetime_str.len() + type_str.len() + 8;
282 let budget = try_opt!(width.checked_sub(used_width));
283 let bounds_str = try_opt!(bounds.iter()
285 ty_bound.rewrite(context,
289 .collect::<Option<Vec<_>>>())
292 format!("for<{}> {}: {}", lifetime_str, type_str, bounds_str)
295 let used_width = type_str.len() + 2;
296 let budget = try_opt!(width.checked_sub(used_width));
297 let bounds_str = try_opt!(bounds.iter()
299 ty_bound.rewrite(context,
303 .collect::<Option<Vec<_>>>())
306 format!("{}: {}", type_str, bounds_str)
309 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { ref lifetime,
313 pprust::lifetime_to_string(lifetime),
315 .map(pprust::lifetime_to_string)
319 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { ref path, ref ty, .. }) => {
320 let ty_str = try_opt!(ty.rewrite(context, width, offset));
322 let used_width = 3 + ty_str.len();
323 let budget = try_opt!(width.checked_sub(used_width));
324 let path_str = try_opt!(rewrite_path(context,
329 offset + used_width));
330 format!("{} = {}", path_str, ty_str)
334 wrap_str(result, context.config.max_width, width, offset)
338 impl Rewrite for ast::LifetimeDef {
339 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
340 let result = if self.bounds.is_empty() {
341 pprust::lifetime_to_string(&self.lifetime)
344 pprust::lifetime_to_string(&self.lifetime),
347 .map(pprust::lifetime_to_string)
352 wrap_str(result, context.config.max_width, width, offset)
356 impl Rewrite for ast::TyParamBound {
357 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
359 ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => {
360 tref.rewrite(context, width, offset)
362 ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::Maybe) => {
363 let budget = try_opt!(width.checked_sub(1));
364 Some(format!("?{}", try_opt!(tref.rewrite(context, budget, offset + 1))))
366 ast::TyParamBound::RegionTyParamBound(ref l) => {
367 wrap_str(pprust::lifetime_to_string(l),
368 context.config.max_width,
376 impl Rewrite for ast::TyParamBounds {
377 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
378 let strs: Vec<_> = try_opt!(self.iter()
379 .map(|b| b.rewrite(context, width, offset))
381 wrap_str(strs.join(" + "), context.config.max_width, width, offset)
385 impl Rewrite for ast::TyParam {
386 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
387 let mut result = String::with_capacity(128);
388 result.push_str(&self.ident.to_string());
389 if !self.bounds.is_empty() {
390 result.push_str(": ");
392 let bounds = try_opt!(self.bounds
394 .map(|ty_bound| ty_bound.rewrite(context, width, offset))
395 .collect::<Option<Vec<_>>>())
398 result.push_str(&bounds);
400 if let Some(ref def) = self.default {
401 result.push_str(" = ");
402 let budget = try_opt!(width.checked_sub(result.len()));
403 let rewrite = try_opt!(def.rewrite(context, budget, offset + result.len()));
404 result.push_str(&rewrite);
407 wrap_str(result, context.config.max_width, width, offset)
411 impl Rewrite for ast::PolyTraitRef {
412 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
413 if !self.bound_lifetimes.is_empty() {
414 let lifetime_str = try_opt!(self.bound_lifetimes
416 .map(|lt| lt.rewrite(context, width, offset))
417 .collect::<Option<Vec<_>>>())
419 // 6 is "for<> ".len()
420 let extra_offset = lifetime_str.len() + 6;
421 let max_path_width = try_opt!(width.checked_sub(extra_offset));
422 let path_str = try_opt!(rewrite_path(context,
425 &self.trait_ref.path,
427 offset + extra_offset));
429 Some(format!("for<{}> {}", lifetime_str, path_str))
431 rewrite_path(context, false, None, &self.trait_ref.path, width, offset)
436 impl Rewrite for ast::Ty {
437 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
439 ast::TyObjectSum(ref ty, ref bounds) => {
440 let ty_str = try_opt!(ty.rewrite(context, width, offset));
441 let overhead = ty_str.len() + 3;
442 Some(format!("{} + {}",
444 try_opt!(bounds.rewrite(context,
445 try_opt!(width.checked_sub(overhead)),
446 offset + overhead))))
448 ast::TyPtr(ref mt) => {
449 let prefix = match mt.mutbl {
450 Mutability::MutMutable => "*mut ",
451 Mutability::MutImmutable => "*const ",
454 rewrite_unary_prefix(context, prefix, &*mt.ty, width, offset)
456 ast::TyRptr(ref lifetime, ref mt) => {
457 let mut_str = format_mutability(mt.mutbl);
458 let mut_len = mut_str.len();
459 Some(match *lifetime {
460 Some(ref lifetime) => {
461 let lt_str = pprust::lifetime_to_string(lifetime);
462 let lt_len = lt_str.len();
463 let budget = try_opt!(width.checked_sub(2 + mut_len + lt_len));
467 try_opt!(mt.ty.rewrite(context,
469 offset + 2 + mut_len + lt_len)))
472 let budget = try_opt!(width.checked_sub(1 + mut_len));
475 try_opt!(mt.ty.rewrite(context, budget, offset + 1 + mut_len)))
479 // FIXME: we drop any comments here, even though it's a silly place to put
481 ast::TyParen(ref ty) => {
482 let budget = try_opt!(width.checked_sub(2));
483 ty.rewrite(context, budget, offset + 1).map(|ty_str| format!("({})", ty_str))
485 ast::TyVec(ref ty) => {
486 let budget = try_opt!(width.checked_sub(2));
487 ty.rewrite(context, budget, offset + 1).map(|ty_str| format!("[{}]", ty_str))
489 ast::TyTup(ref items) => rewrite_tuple(context, items, self.span, width, offset),
490 ast::TyPolyTraitRef(ref trait_ref) => trait_ref.rewrite(context, width, offset),
491 ast::TyPath(ref q_self, ref path) => {
492 rewrite_path(context, false, q_self.as_ref(), path, width, offset)
494 ast::TyFixedLengthVec(ref ty, ref repeats) => {
495 rewrite_pair(&**ty, &**repeats, "[", "; ", "]", context, width, offset)
504 ast::TyBareFn(ref bare_fn) => bare_fn.rewrite(context, width, offset),
505 ast::TyMac(..) | ast::TyTypeof(..) => unreachable!(),
510 impl Rewrite for ast::BareFnTy {
511 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {