From 2d4b4b856a691578e6962406d6ca34b3b7582edf Mon Sep 17 00:00:00 2001 From: Marcus Klaas Date: Thu, 2 Jul 2015 22:40:20 +0200 Subject: [PATCH] Format expressions with binary and unary operators --- src/expr.rs | 95 ++++++++++++++++++++++++++++++++++--------- tests/source/expr.rs | 14 +++++++ tests/target/expr.rs | 14 +++++++ tests/target/paren.rs | 7 ---- 4 files changed, 104 insertions(+), 26 deletions(-) create mode 100644 tests/source/expr.rs create mode 100644 tests/target/expr.rs delete mode 100644 tests/target/paren.rs diff --git a/src/expr.rs b/src/expr.rs index d66630e5179..2f97fa7e97a 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -11,7 +11,7 @@ use rewrite::{Rewrite, RewriteContext}; use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic}; use string::{StringFormat, rewrite_string}; -use utils::span_after; +use utils::{span_after, make_indent}; use syntax::{ast, ptr}; use syntax::codemap::{Pos, Span, BytePos}; @@ -24,35 +24,37 @@ impl Rewrite for ast::Expr { ast::Expr_::ExprLit(ref l) => { match l.node { ast::Lit_::LitStr(ref is, _) => { - let result = rewrite_string_lit(context, &is, l.span, width, offset); - debug!("string lit: `{:?}`", result); - return result; + rewrite_string_lit(context, &is, l.span, width, offset) } - _ => {} + _ => context.codemap.span_to_snippet(self.span).ok() } } ast::Expr_::ExprCall(ref callee, ref args) => { - return rewrite_call(context, callee, args, self.span, width, offset); + rewrite_call(context, callee, args, self.span, width, offset) } ast::Expr_::ExprParen(ref subexpr) => { - return rewrite_paren(context, subexpr, width, offset); + rewrite_paren(context, subexpr, width, offset) + } + ast::Expr_::ExprBinary(ref op, ref lhs, ref rhs) => { + rewrite_binary_op(context, op, lhs, rhs, width, offset) + } + ast::Expr_::ExprUnary(ref op, ref subexpr) => { + rewrite_unary_op(context, op, subexpr, width, offset) } ast::Expr_::ExprStruct(ref path, ref fields, ref base) => { - return rewrite_struct_lit(context, - path, - fields, - base.as_ref().map(|e| &**e), - self.span, - width, - offset); + rewrite_struct_lit(context, + path, + fields, + base.as_ref().map(|e| &**e), + self.span, + width, + offset) } ast::Expr_::ExprTup(ref items) => { - return rewrite_tuple_lit(context, items, self.span, width, offset); + rewrite_tuple_lit(context, items, self.span, width, offset) } - _ => {} + _ => context.codemap.span_to_snippet(self.span).ok() } - - context.codemap.span_to_snippet(self.span).ok() } } @@ -235,7 +237,7 @@ fn rewrite_tuple_lit(context: &RewriteContext, span: Span, width: usize, offset: usize) - -> Option { + -> Option { let indent = offset + 1; let items = itemize_list(context.codemap, @@ -272,3 +274,58 @@ fn rewrite_tuple_lit(context: &RewriteContext, Some(format!("({})", write_list(&items, &fmt))) } + +fn rewrite_binary_op(context: &RewriteContext, + op: &ast::BinOp, + lhs: &ast::Expr, + rhs: &ast::Expr, + width: usize, + offset: usize) + -> Option { + // FIXME: format comments between operands and operator + + let operator_str = context.codemap.span_to_snippet(op.span).unwrap(); + + // 1 = space between lhs expr and operator + let mut result = try_opt!(lhs.rewrite(context, width - 1 - operator_str.len(), offset)); + + result.push(' '); + result.push_str(&operator_str); + + let remaining_width = match result.rfind('\n') { + Some(idx) => (context.config.max_width + idx).checked_sub(result.len()).unwrap_or(0), + None => width.checked_sub(result.len()).unwrap_or(0) + }; + + // Get "full width" rhs and see if it fits on the current line. This + // usually works fairly well since it tends to place operands of + // operations with high precendence close together. + let rhs_result = try_opt!(rhs.rewrite(context, width, offset)); + + if rhs_result.len() > remaining_width { + result.push('\n'); + result.push_str(&make_indent(offset)); + } else { + result.push(' '); + }; + + result.push_str(&rhs_result); + Some(result) +} + +fn rewrite_unary_op(context: &RewriteContext, + op: &ast::UnOp, + expr: &ast::Expr, + width: usize, + offset: usize) + -> Option { + // For some reason, an UnOp is not spanned like BinOp! + let operator_str = match *op { + ast::UnOp::UnUniq => "&", + ast::UnOp::UnDeref => "*", + ast::UnOp::UnNot => "!", + ast::UnOp::UnNeg => "-" + }; + + Some(format!("{}{}", operator_str, try_opt!(expr.rewrite(context, width - 1, offset)))) +} diff --git a/tests/source/expr.rs b/tests/source/expr.rs new file mode 100644 index 00000000000..d7013a312f1 --- /dev/null +++ b/tests/source/expr.rs @@ -0,0 +1,14 @@ +// Test expressions + +fn foo() -> bool { + let very_long_variable_name = ( a + first + simple + test ); + let very_long_variable_name = (a + first + simple + test + AAAAAAAAAAAAA + BBBBBBBBBBBBBBBBB + b + c); + + let some_val = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * bbbb / (bbbbbb - + function_call(x, *very_long_pointer, y)) + + 1000; + +some_ridiculously_loooooooooooooooooooooong_function(10000 * 30000000000 + 40000 / 1002200000000 + - 50000 * sqrt(-1), + trivial_value) +} diff --git a/tests/target/expr.rs b/tests/target/expr.rs new file mode 100644 index 00000000000..c565c94b2ac --- /dev/null +++ b/tests/target/expr.rs @@ -0,0 +1,14 @@ +// Test expressions + +fn foo() -> bool { + let very_long_variable_name = (a + first + simple + test); + let very_long_variable_name = (a + first + simple + test + AAAAAAAAAAAAA + BBBBBBBBBBBBBBBBB + + b + c); + + let some_val = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * bbbb / + (bbbbbb - function_call(x, *very_long_pointer, y)) + 1000; + + some_ridiculously_loooooooooooooooooooooong_function(10000 * 30000000000 + + 40000 / 1002200000000 - 50000 * sqrt(-1), + trivial_value) +} diff --git a/tests/target/paren.rs b/tests/target/paren.rs deleted file mode 100644 index 98169883575..00000000000 --- a/tests/target/paren.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Test parenthesis - -fn foo() { - let very_long_variable_name = (a + first + simple + test); - let very_long_variable_name = (a + first + simple + test + AAAAAAAAAAAAA + BBBBBBBBBBBBBBBBBB + - b + c); -}