diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 0077bed0fe..37faea9f53 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -11,7 +11,8 @@ const ( tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t' ] - max_len = 90 + // when to break a line dependant on penalty + max_len = [0, 30, 85, 100] ) pub struct Fmt { @@ -439,7 +440,7 @@ pub fn (mut f Fmt) type_decl(node ast.TypeDecl) { if i < sum_type_names.len - 1 { f.write(' | ') } - f.wrap_long_line() + f.wrap_long_line(2, true) } // f.write(sum_type_names.join(' | ')) } @@ -629,7 +630,14 @@ pub fn (mut f Fmt) expr(node ast.Expr) { f.write('$node.op.str()') } else { f.write(' $node.op.str() ') - f.wrap_long_line() + mut penalty := 3 + if node.left is ast.InfixExpr || node.left is ast.ParExpr { + penalty-- + } + if node.right is ast.InfixExpr || node.right is ast.ParExpr { + penalty-- + } + f.wrap_long_line(penalty, true) } f.expr(node.right) } @@ -788,14 +796,14 @@ pub fn (mut f Fmt) expr(node ast.Expr) { } } -pub fn (mut f Fmt) wrap_long_line() bool { - if f.line_len <= max_len { +pub fn (mut f Fmt) wrap_long_line(penalty int, add_indent bool) bool { + if f.line_len <= max_len[penalty] { return false } if f.out.buf[f.out.buf.len - 1] == ` ` { f.out.go_back(1) } - f.write('\n' + tabs[f.indent + 1]) + f.write('\n' + tabs[f.indent + if add_indent { 1 } else { 0 }]) f.line_len = 0 return true } @@ -806,7 +814,7 @@ pub fn (mut f Fmt) call_args(args []ast.CallArg) { f.write('mut ') } if i > 0 { - f.wrap_long_line() + f.wrap_long_line(2, true) } f.expr(arg.expr) if i < args.len - 1 { @@ -1193,15 +1201,24 @@ pub fn (mut f Fmt) array_init(it ast.ArrayInit) { mut inc_indent := false mut last_line_nr := it.pos.line_nr // to have the same newlines between array elements for i, expr in it.exprs { + mut penalty := 3 line_nr := expr.position().line_nr if last_line_nr < line_nr { - if !inc_indent { - f.indent++ - inc_indent = true - } - f.writeln('') + penalty-- + } + if i == 0 || it.exprs[i-1] is ast.ArrayInit || it.exprs[i-1] is ast.StructInit || + it.exprs[i-1] is ast.MapInit || it.exprs[i-1] is ast.CallExpr { + penalty-- + } + if expr is ast.ArrayInit || expr is ast.StructInit || + expr is ast.MapInit || expr is ast.CallExpr { + penalty-- + } + is_new_line := f.wrap_long_line(penalty, !inc_indent) + if is_new_line && !inc_indent { + f.indent++ + inc_indent = true } - is_new_line := last_line_nr < line_nr || f.wrap_long_line() if !is_new_line && i > 0 { f.write(' ') } diff --git a/vlib/v/fmt/tests/consts_expected.vv b/vlib/v/fmt/tests/consts_expected.vv index 61d27ba684..1fcf0b57ec 100644 --- a/vlib/v/fmt/tests/consts_expected.vv +++ b/vlib/v/fmt/tests/consts_expected.vv @@ -6,13 +6,9 @@ const ( eulers = 2.7182 supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd', 'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos'] - one_line_supported = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd', - 'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos'] - another_const = [ - 'a', 'b', - 'c', 'd', 'e', - 'f' - ] + one_line_supported = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd', 'netbsd', + 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos'] + another_const = ['a', 'b', 'c', 'd', 'e', 'f'] ) const ( diff --git a/vlib/v/fmt/tests/expressions_expected.vv b/vlib/v/fmt/tests/expressions_expected.vv new file mode 100644 index 0000000000..3bc8910cb7 --- /dev/null +++ b/vlib/v/fmt/tests/expressions_expected.vv @@ -0,0 +1,41 @@ +import v.checker +import v.ast +import v.table + +pub fn string_inter_lit(mut c checker.Checker, mut node ast.StringInterLiteral) table.Type { + for i, expr in node.exprs { + ftyp := c.expr(expr) + node.expr_types << ftyp + typ := c.table.unalias_num_type(ftyp) + mut fmt := node.fmts[i] + // analyze and validate format specifier + if fmt !in [`E`, `F`, `G`, `e`, `f`, `g`, `d`, `u`, `x`, `X`, `o`, `c`, `s`, `p`, `_`] { + c.error('unknown format specifier `${fmt:c}`', node.fmt_poss[i]) + } + if node.precisions[i] != 0 && !typ.is_float() { + c.error('precision specification only valid for float types', node.fmt_poss[i]) + } + if node.pluss[i] && !typ.is_number() { + c.error('plus prefix only allowd for numbers', node.fmt_poss[i]) + } + if (typ.is_unsigned() && fmt !in [`u`, `x`, `X`, `o`, `c`]) || + (typ.is_signed() && fmt !in [`d`, `x`, `X`, `o`, `c`]) || + (typ.is_any_int() && fmt !in [`d`, `c`, `x`, `X`, `o`, `u`, `x`, `X`, `o`]) || + (typ.is_float() && fmt !in [`E`, `F`, `G`, `e`, `f`, `g`]) || + (typ.is_pointer() && fmt !in [`p`, `x`, `X`]) || + (typ.is_string() && fmt != `s`) || + (typ.idx() in [table.i64_type_idx, table.f64_type_idx] && + fmt == `c`) { + c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`', + node.fmt_poss[i]) + } + node.need_fmts[i] = fmt != c.get_default_fmt(ftyp, typ) + } + return table.string_type +} + +fn get_some_val(a_test, b_test, c_test, d_test, e_test, f_test f64) { + return a_test * b_test * c_test * d_test + + e_test * f_test * a_test * d_test + + a_test * b_test * c_test +} diff --git a/vlib/v/fmt/tests/expressions_input.vv b/vlib/v/fmt/tests/expressions_input.vv new file mode 100644 index 0000000000..f37008a79e --- /dev/null +++ b/vlib/v/fmt/tests/expressions_input.vv @@ -0,0 +1,47 @@ +import v.checker +import v.ast +import v.table + +pub fn string_inter_lit(mut c checker.Checker, mut node ast.StringInterLiteral) table.Type { + for i, expr in node.exprs { + ftyp := c.expr(expr) + node.expr_types << ftyp + typ := c.table.unalias_num_type(ftyp) + mut fmt := node.fmts[i] + // analyze and validate format specifier + if fmt !in [`E`, `F`, `G`, `e`, `f`, `g`, + `d`, `u`, `x`, `X`, `o`, `c`, `s`, `p`, `_`] { + c.error('unknown format specifier `${fmt:c}`', + node.fmt_poss[i]) + } + if node.precisions[i] != 0 && + !typ.is_float() { + c.error('precision specification only valid for float types', + node.fmt_poss[i]) + } + if node.pluss[i] && !typ.is_number() { + c.error('plus prefix only allowd for numbers', node.fmt_poss[i]) + } + if (typ.is_unsigned() && fmt !in [`u`, `x`, `X`, `o`, `c`]) || (typ.is_signed() && + fmt !in [`d`, `x`, `X`, `o`, `c`]) || (typ.is_any_int() + && fmt !in [`d`, `c`, `x`, `X`, `o`, + `u`, `x`, `X`, `o`]) || (typ.is_float() && fmt !in [`E`, `F`, + `G`, `e`, `f`, `g`]) || (typ.is_pointer() && + fmt !in [`p`, `x`, `X`]) || (typ.is_string() && fmt != `s`) + || (typ.idx() in [table.i64_type_idx, + table.f64_type_idx + ] && fmt == `c`) { + c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`', + node.fmt_poss[i]) + } + node.need_fmts[i] = fmt != c.get_default_fmt(ftyp, typ) + } + + return table.string_type +} + +fn get_some_val(a_test, b_test, c_test, d_test, e_test, f_test f64) { + return a_test*b_test*c_test* + d_test+e_test*f_test*a_test*d_test+a_test* + b_test*c_test +}