Skip to content

Commit 74050a4

Browse files
makenowjustMartin Verzilli
authored and
Martin Verzilli
committedSep 17, 2017
Refactor 'Crystal::Formatter#format_def_args' (#4992)
Fix #1924 Close #4980, #4990 This is just refactoring but it contains many bug fixes and improvements. These come from refactoring effects, so I cannot separate them from this. Bug fixes and improvements: - work formatting double splat with trailing comma (#4990) - work formatting when there is newline or comment between argument and comma. ```crystal def foo(a ,) end def foo(a # comment ,) end ``` is formatted to correctly: ```crystal def foo(a) end def foo(a # comment ) end ``` - format arguments with 2 spaces indentation (#1924) - distinguish comment followed on newline and argument. The formatter keeps this for example: ```crystal def foo(a # argument 'a' is ... ) end def foo(a # more argument here in future... ) end ``` And, perhaps there are other bug fixes and improvements because `format_def_args` has too many bugs to remember. Refactoring is so great!! * Rename 'wrote_newline' inside 'format_def_arg' to 'just_wrote_newline' And fix some conditions for readbility.
1 parent af8c4f6 commit 74050a4

File tree

4 files changed

+116
-169
lines changed

4 files changed

+116
-169
lines changed
 

Diff for: ‎spec/compiler/formatter/formatter_spec.cr

+14-5
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ describe Crystal::Formatter do
157157
assert_format "def foo ( x , y , ) \n end", "def foo(x, y)\nend"
158158
assert_format "def foo ( x , y ,\n) \n end", "def foo(x, y)\nend"
159159
assert_format "def foo ( x ,\n y ) \n end", "def foo(x,\n y)\nend"
160-
assert_format "def foo (\nx ,\n y ) \n end", "def foo(\n x,\n y)\nend"
160+
assert_format "def foo (\nx ,\n y ) \n end", "def foo(\n x,\n y\n)\nend"
161+
assert_format "class Foo\ndef foo (\nx ,\n y ) \n end\nend", "class Foo\n def foo(\n x,\n y\n )\n end\nend"
161162
assert_format "def foo ( @x) \n end", "def foo(@x)\nend"
162163
assert_format "def foo ( @x, @y) \n end", "def foo(@x, @y)\nend"
163164
assert_format "def foo ( @@x) \n end", "def foo(@@x)\nend"
@@ -581,6 +582,7 @@ describe Crystal::Formatter do
581582
assert_format "lib Foo\nfun foo(x : Int32, ... ) : Int32\nend", "lib Foo\n fun foo(x : Int32, ...) : Int32\nend"
582583
assert_format "lib Foo\n fun foo(Int32) : Int32\nend"
583584
assert_format "fun foo(x : Int32) : Int32\n 1\nend"
585+
assert_format "fun foo(\n x : Int32,\n ...\n) : Int32\n 1\nend"
584586
assert_format "lib Foo\n fun foo = bar(Int32) : Int32\nend"
585587
assert_format "lib Foo\n fun foo = \"bar\"(Int32) : Int32\nend"
586588
assert_format "lib Foo\n $foo : Int32 \nend", "lib Foo\n $foo : Int32\nend"
@@ -742,8 +744,8 @@ describe Crystal::Formatter do
742744
assert_format "foo(\n# x\n1,\n\n# y\nz: 2\n)", "foo(\n # x\n 1,\n\n # y\n z: 2\n)"
743745
assert_format "foo(\n# x\n1,\n\n# y\nz: 2,\n\n# a\nb: 3)", "foo(\n # x\n 1,\n\n # y\n z: 2,\n\n # a\n b: 3)"
744746
assert_format "foo(\n 1, # hola\n2, # chau\n )", "foo(\n 1, # hola\n 2, # chau\n)"
745-
assert_format "def foo(\n\n#foo\nx,\n\n#bar\nz\n)\nend", "def foo(\n # foo\n x,\n\n # bar\n z)\nend"
746-
assert_format "def foo(\nx, #foo\nz #bar\n)\nend", "def foo(\n x, # foo\n z # bar\n )\nend"
747+
assert_format "def foo(\n\n#foo\nx,\n\n#bar\nz\n)\nend", "def foo(\n # foo\n x,\n\n # bar\n z\n)\nend"
748+
assert_format "def foo(\nx, #foo\nz #bar\n)\nend", "def foo(\n x, # foo\n z # bar\n)\nend"
747749
assert_format "a = 1;;; b = 2", "a = 1; b = 2"
748750
assert_format "a = 1\n;\nb = 2", "a = 1\nb = 2"
749751
assert_format "foo do\n # bar\nend"
@@ -1017,11 +1019,18 @@ describe Crystal::Formatter do
10171019
assert_format "foo(A |\nB |\nC)", "foo(A |\n B |\n C)"
10181020
assert_format "def foo\n case x\n # z\n when 1\n end\nend"
10191021
assert_format "foo { |x| (x).a }"
1020-
assert_format "def foo(\n &block)\nend"
1022+
assert_format "def foo(\n &block\n)\nend"
10211023
assert_format "def foo(a,\n &block)\nend"
1022-
assert_format "def foo(\n a,\n &block)\nend"
1024+
assert_format "def foo(\n a,\n &block\n)\nend"
10231025
assert_format "def foo(a,\n *b)\nend"
1026+
assert_format "def foo(a\n, *b)\nend", "def foo(a,\n *b)\nend"
1027+
assert_format "def foo(a # comment\n, *b)\nend", "def foo(a, # comment\n *b)\nend"
10241028
assert_format "def foo(a,\n **b)\nend"
1029+
assert_format "def foo(\n **a\n)\n 1\nend"
1030+
assert_format "def foo(**a,)\n 1\nend", "def foo(**a)\n 1\nend"
1031+
assert_format "def foo(\n **a # comment\n)\n 1\nend"
1032+
assert_format "def foo(\n **a\n # comment\n)\n 1\nend"
1033+
assert_format "def foo(\n **a\n\n # comment\n)\n 1\nend"
10251034
assert_format "def foo(**b, # comment\n &block)\nend"
10261035
assert_format "def foo(a, **b, # comment\n &block)\nend"
10271036

Diff for: ‎src/compiler/crystal/tools/formatter.cr

+89-153
Original file line numberDiff line numberDiff line change
@@ -1390,190 +1390,126 @@ module Crystal
13901390
end
13911391

13921392
def format_def_args(args : Array, block_arg, splat_index, variadic, double_splat)
1393-
to_skip = 0
1394-
1395-
# If there are no args, remove extra "()", if any
1396-
if args.empty?
1393+
# If there are no args, remove extra "()"
1394+
if args.empty? && !block_arg && !double_splat && !variadic
13971395
if @token.type == :"("
1398-
prefix_size = @column + 1
1399-
1400-
write "(" if block_arg || double_splat || variadic
1401-
next_token
1402-
1403-
skip_space
1404-
if @token.type == :NEWLINE
1405-
write_line
1406-
write_indent(prefix_size)
1407-
skip_space_or_newline(prefix_size)
1408-
end
1409-
1410-
if double_splat
1411-
write_token :"**"
1412-
double_splat.accept self
1413-
skip_space_or_newline
1414-
end
1415-
1416-
if block_arg
1417-
if double_splat
1418-
write_token :","
1419-
found_comment = skip_space_or_newline
1420-
if found_comment
1421-
write_indent(prefix_size)
1422-
else
1423-
write " "
1424-
end
1425-
end
1426-
write_token :"&"
1427-
skip_space
1428-
to_skip += 1 if at_skip?
1429-
accept block_arg
1430-
skip_space_or_newline
1431-
end
1432-
1433-
if variadic
1434-
skip_space_or_newline
1435-
write_token :"..."
1436-
skip_space_or_newline
1437-
end
1438-
1396+
next_token_skip_space_or_newline
14391397
check :")"
14401398
next_token
1441-
write ")" if block_arg || double_splat || variadic
14421399
end
1443-
else
1444-
prefix_size = @column + 1
1400+
return 0
1401+
end
14451402

1446-
old_indent = @indent
1447-
next_needs_indent = false
1448-
has_parentheses = false
1449-
found_comment = false
1403+
# Count instance variable arguments. See `at_skip?`.
1404+
to_skip = 0
14501405

1451-
if @token.type == :"("
1452-
has_parentheses = true
1453-
write "("
1454-
next_token_skip_space
1455-
if @token.type == :NEWLINE
1456-
write_line
1457-
skip_space_or_newline(prefix_size)
1458-
next_needs_indent = true
1459-
end
1460-
skip_space_or_newline
1461-
else
1462-
write "("
1463-
end
1406+
wrote_newline = false
1407+
found_first_newline = false
14641408

1465-
comma_written = false
1409+
old_indent = @indent
1410+
@indent = @column + 1
14661411

1467-
args.each_with_index do |arg, i|
1468-
if next_needs_indent
1469-
write_indent(prefix_size)
1470-
end
1412+
write_token :"("
1413+
skip_space
1414+
1415+
# When "(" follows newline, it turns on two spaces indentation mode.
1416+
if @token.type == :NEWLINE
1417+
@indent = old_indent + 2
1418+
found_first_newline = true
1419+
wrote_newline = true
14711420

1421+
write_line
1422+
next_token_skip_space_or_newline
1423+
end
1424+
1425+
args.each_with_index do |arg, i|
1426+
has_more = !last?(i, args) || double_splat || block_arg || variadic
1427+
wrote_newline = format_def_arg(wrote_newline, has_more) do
14721428
if i == splat_index
14731429
write_token :"*"
14741430
skip_space_or_newline
1431+
next if arg.external_name.empty? # skip empty splat argument.
14751432
end
14761433

1477-
if i == splat_index && arg.external_name.empty?
1478-
# Nothing
1479-
else
1480-
indent(prefix_size, arg)
1481-
to_skip += 1 if @last_arg_is_skip
1482-
end
1483-
1484-
skip_space
1485-
1486-
if @token.type == :","
1487-
has_more = !last?(i, args) || double_splat || block_arg
1488-
1489-
if has_more
1490-
write ","
1491-
comma_written = true
1492-
end
1493-
next_token
1494-
found_comment = skip_space
1495-
if @token.type == :NEWLINE
1496-
if has_more
1497-
indent(prefix_size) { consume_newlines }
1498-
next_needs_indent = true
1499-
end
1500-
elsif found_comment
1501-
next_needs_indent = true
1502-
else
1503-
next_needs_indent = false
1504-
write " " if has_more
1505-
end
1506-
skip_space_or_newline
1507-
else
1508-
comma_written = false
1509-
end
1434+
arg.accept self
1435+
to_skip += 1 if @last_arg_is_skip
15101436
end
1437+
end
15111438

1512-
if double_splat
1513-
if next_needs_indent
1514-
write_indent(prefix_size)
1515-
next_needs_indent = false
1516-
end
1517-
unless comma_written
1518-
write ", "
1519-
comma_written = true
1520-
end
1439+
if double_splat
1440+
wrote_newline = format_def_arg(wrote_newline, block_arg) do
15211441
write_token :"**"
1522-
double_splat.accept self
15231442
skip_space_or_newline
1524-
if block_arg
1525-
check :","
1526-
write ","
1527-
comma_written = true
1528-
found_comment = next_token_skip_space
1529-
if found_comment
1530-
next_needs_indent = true
1531-
found_comment = false
1532-
else
1533-
if @token.type == :NEWLINE
1534-
indent(prefix_size) { consume_newlines }
1535-
next_needs_indent = true
1536-
else
1537-
write " "
1538-
end
1539-
end
1540-
end
1443+
1444+
to_skip += 1 if at_skip?
1445+
double_splat.accept self
15411446
end
1447+
end
15421448

1543-
if block_arg
1544-
if next_needs_indent
1545-
write_indent(prefix_size)
1546-
next_needs_indent = false
1547-
end
1548-
unless comma_written
1549-
write ", "
1550-
comma_written = true
1551-
end
1449+
if block_arg
1450+
wrote_newline = format_def_arg(wrote_newline, false) do
15521451
write_token :"&"
1553-
skip_space
1452+
skip_space_or_newline
1453+
15541454
to_skip += 1 if at_skip?
1555-
accept block_arg
1556-
skip_space
1455+
block_arg.accept self
15571456
end
1457+
end
15581458

1559-
if variadic
1560-
write_token ", ", :"..."
1561-
skip_space_or_newline
1459+
if variadic
1460+
wrote_newline = format_def_arg(wrote_newline, false) do
1461+
write_token :"..."
15621462
end
1463+
end
15631464

1564-
if has_parentheses
1565-
skip_space_or_newline
1566-
write_indent(prefix_size) if found_comment
1567-
write_token :")"
1465+
if found_first_newline && !wrote_newline
1466+
write_line
1467+
wrote_newline = true
1468+
end
1469+
write_indent(found_first_newline ? old_indent : @indent) if wrote_newline
1470+
write_token :")"
1471+
1472+
@indent = old_indent
1473+
1474+
to_skip
1475+
end
1476+
1477+
def format_def_arg(wrote_newline, has_more)
1478+
write_indent if wrote_newline
1479+
1480+
yield
1481+
1482+
# Write "," before skipping spaces to prevent inserting comment between argument and comma.
1483+
write "," if has_more
1484+
1485+
just_wrote_newline = skip_space
1486+
if @token.type == :NEWLINE
1487+
if has_more
1488+
consume_newlines
1489+
just_wrote_newline = true
15681490
else
1569-
write_indent(prefix_size) if found_comment
1570-
write ")"
1491+
# `last: true` is needed to write newline and comment only if comment is found.
1492+
just_wrote_newline = skip_space_or_newline(last: true)
15711493
end
1494+
end
15721495

1573-
@indent = old_indent
1496+
if @token.type == :","
1497+
found_comment = next_token_skip_space
1498+
if found_comment
1499+
just_wrote_newline = true
1500+
elsif @token.type == :NEWLINE
1501+
if has_more && !just_wrote_newline
1502+
consume_newlines
1503+
just_wrote_newline = true
1504+
else
1505+
just_wrote_newline |= skip_space_or_newline(last: true)
1506+
end
1507+
else
1508+
write " " if has_more && !just_wrote_newline
1509+
end
15741510
end
15751511

1576-
to_skip
1512+
just_wrote_newline
15771513
end
15781514

15791515
# The parser transforms `def foo(@x); end` to `def foo(x); @x = x; end` so if we

Diff for: ‎src/compiler/crystal/tools/init.cr

+8-7
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,14 @@ module Crystal
102102
property silent : Bool
103103

104104
def initialize(
105-
@skeleton_type = "none",
106-
@name = "none",
107-
@dir = "none",
108-
@author = "none",
109-
@email = "none",
110-
@github_name = "none",
111-
@silent = false)
105+
@skeleton_type = "none",
106+
@name = "none",
107+
@dir = "none",
108+
@author = "none",
109+
@email = "none",
110+
@github_name = "none",
111+
@silent = false
112+
)
112113
end
113114
end
114115

Diff for: ‎src/llvm/lib_llvm_ext.cr

+5-4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ lib LibLLVMExt
1414
fun di_builder_finalize = LLVMDIBuilderFinalize(DIBuilder)
1515

1616
fun di_builder_create_function = LLVMDIBuilderCreateFunction(
17-
builder : DIBuilder, scope : Metadata, name : Char*,
18-
linkage_name : Char*, file : Metadata, line : UInt,
19-
composite_type : Metadata, is_local_to_unit : Bool, is_definition : Bool,
20-
scope_line : UInt, flags : LLVM::DIFlags, is_optimized : Bool, func : LibLLVM::ValueRef) : Metadata
17+
builder : DIBuilder, scope : Metadata, name : Char*,
18+
linkage_name : Char*, file : Metadata, line : UInt,
19+
composite_type : Metadata, is_local_to_unit : Bool, is_definition : Bool,
20+
scope_line : UInt, flags : LLVM::DIFlags, is_optimized : Bool, func : LibLLVM::ValueRef
21+
) : Metadata
2122

2223
fun di_builder_create_file = LLVMDIBuilderCreateFile(builder : DIBuilder, file : Char*, dir : Char*) : Metadata
2324
fun di_builder_create_compile_unit = LLVMDIBuilderCreateCompileUnit(builder : DIBuilder,

0 commit comments

Comments
 (0)
Please sign in to comment.