Skip to content

More robust trailing expressions newline implementation #15614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions spec/compiler/parser/parser_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2851,6 +2851,33 @@ module Crystal
else_node_location.line_number.should eq 7
end

it "sets root level Expressions keyword" do
parser = Parser.new(<<-CR)
{%
a = 1

if true
arr << 1
arr << 2
end

b = 2
c = 3
%}
CR

node = parser.parse.should be_a MacroExpression

node = node.exp.should be_a Expressions
node.keyword.should eq Expressions::Keyword::MacroExpression

node.expressions.size.should eq 4
node = node.expressions[1].should be_a If
node = node.then.should be_a Expressions

node.keyword.should eq Expressions::Keyword::None
end

it "sets correct location of Begin within another node" do
parser = Parser.new(<<-CR)
macro finished
Expand Down
80 changes: 80 additions & 0 deletions spec/compiler/parser/to_s_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,24 @@ describe "ASTNode#to_s" do
expect_to_s "{%\n a = 1 %}"
expect_to_s "{% a = 1\n%}"

expect_to_s <<-'CR', <<-'CR'
{%
10

# Foo

20
%}
CR
{%
10



20
%}
CR

expect_to_s <<-'CR', <<-'CR'
macro finished
{% verbatim do %}
Expand Down Expand Up @@ -444,6 +462,68 @@ describe "ASTNode#to_s" do
end
CR

expect_to_s <<-CR
{%
a = 1

if true
b = 2
c = 3
end

d = 4
%}
CR

expect_to_s <<-CR
{%
arr.each do |c|
c.each do
to_process << 1
to_process << 2
end
end

to_process.each do
b = 2
a = 1
end
%}
CR

expect_to_s <<-CR
{%
a = 1

unless false
b = 2
c = 3
end

d = 4
%}
CR

expect_to_s <<-CR
{%
arr.each do
b = 2
a = 1
end

c = 3
%}
CR

expect_to_s <<-CR
{%
arr.each do
b = 2
a = 1
end
%}
CR

expect_to_s %(asm("nop" ::::))
expect_to_s %(asm("nop" : "a"(1), "b"(2) : "c"(3), "d"(4) : "e", "f" : "volatile", "alignstack", "intel"))
expect_to_s %(asm("nop" :: "c"(3), "d"(4) ::))
Expand Down
1 change: 1 addition & 0 deletions src/compiler/crystal/syntax/ast.cr
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ module Crystal
None
Paren
Begin
MacroExpression
end

property expressions : Array(ASTNode)
Expand Down
1 change: 1 addition & 0 deletions src/compiler/crystal/syntax/parser.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3444,6 +3444,7 @@ module Crystal

@in_macro_expression = true
exps = parse_expressions
exps.keyword = :macro_expression if exps.is_a? Expressions
@in_macro_expression = false

MacroExpression.new(exps, output: false).at(location).at_end(token_end_location)
Expand Down
18 changes: 7 additions & 11 deletions src/compiler/crystal/syntax/to_s.cr
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ module Crystal
@str : IO
@macro_expansion_pragmas : Hash(Int32, Array(Lexer::LocPragma))?
@current_arg_type : DefArgType = :none
@write_trailing_newline : Bool = true

# Inside a comma-separated list of parameters or args, this becomes true and
# the outermost pair of parentheses are removed from type restrictions that
Expand Down Expand Up @@ -274,7 +273,7 @@ module Crystal
@str << "begin"
@indent += 1
newline
in .none?
in .none?, .macro_expression?
# Not a special condition
end

Expand All @@ -290,10 +289,11 @@ module Crystal
append_indent unless node.keyword.paren? && i == 0
exp.accept self

if !@write_trailing_newline && i == node.expressions.size - 1
# no-op
else
newline unless node.keyword.paren? && i == node.expressions.size - 1
if node.keyword.macro_expression? && i == node.expressions.size - 1
# Do not add a trailing newline after the last node in the root `Expressions` within a `MacroExpression`.
# This is handled by the `MacroExpression` logic.
elsif !(node.keyword.paren? && i == node.expressions.size - 1)
newline
end

last_node = exp
Expand All @@ -308,7 +308,7 @@ module Crystal
@indent -= 1
append_indent
@str << "end"
in .none?
in .none?, .macro_expression?
# Not a special condition
end

Expand Down Expand Up @@ -823,11 +823,7 @@ module Crystal
append_indent
end

# Only skip writing trailing newlines when the macro expressions' expression is not an Expressions.
# This allow Expressions that may be nested deeper in the AST to include trailing newlines.
@write_trailing_newline = !node.exp.is_a?(Expressions)
node.exp.accept self
@write_trailing_newline = true
end

write_extra_newlines node.exp.end_location, node.end_location
Expand Down