From f7b723c6b628bc5b66655130da5f8d8dc900a19a Mon Sep 17 00:00:00 2001 From: TSUYUSATO Kitsune Date: Tue, 2 Feb 2021 07:59:34 +0900 Subject: [PATCH] Parser: refactor 'foo.%` call parsing Fixed #10296 Currently, `%` call parsing is specialized like `if current_char == '%'` way in the parser, to avoid a confliction with `%`-string literals. However, the lexer has `wants_def_or_macro_name` flag for such things, we should use this instead of custom `if` way. The commit fixes the formatter also to set `wants_def_or_macro_name` flag correctly. --- spec/compiler/formatter/formatter_spec.cr | 4 ++++ src/compiler/crystal/syntax/parser.cr | 25 +++++++++-------------- src/compiler/crystal/tools/formatter.cr | 8 ++++++-- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/spec/compiler/formatter/formatter_spec.cr b/spec/compiler/formatter/formatter_spec.cr index efb9d5f5a747..76cd16bb7a03 100644 --- a/spec/compiler/formatter/formatter_spec.cr +++ b/spec/compiler/formatter/formatter_spec.cr @@ -294,6 +294,10 @@ describe Crystal::Formatter do assert_format "foo(1, ) do\nend", "foo(1) do\nend" assert_format "foo {;1}", "foo { 1 }" assert_format "foo {;;1}", "foo { 1 }" + assert_format "foo.%(bar)" + assert_format "foo.% bar" + assert_format "foo.bar(&.%(baz))" + assert_format "foo.bar(&.% baz)" assert_format "foo.bar\n.baz", "foo.bar\n .baz" assert_format "foo.bar.baz\n.qux", "foo.bar.baz\n .qux" diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr index 2bd4c821e1e1..630f629cca58 100644 --- a/src/compiler/crystal/syntax/parser.cr +++ b/src/compiler/crystal/syntax/parser.cr @@ -637,23 +637,18 @@ module Crystal @wants_regex = false - if current_char == '%' - next_char - @token.type = :"%" - @token.column_number += 1 - skip_space_or_newline - else - next_token_skip_space_or_newline + @wants_def_or_macro_name = true + next_token_skip_space_or_newline + @wants_def_or_macro_name = false - if @token.type == :INSTANCE_VAR - ivar_name = @token.value.to_s - end_location = token_end_location - next_token_skip_space + if @token.type == :INSTANCE_VAR + ivar_name = @token.value.to_s + end_location = token_end_location + next_token_skip_space - atomic = ReadInstanceVar.new(atomic, ivar_name).at(location) - atomic.end_location = end_location - next - end + atomic = ReadInstanceVar.new(atomic, ivar_name).at(location) + atomic.end_location = end_location + next end check AtomicWithMethodCheck diff --git a/src/compiler/crystal/tools/formatter.cr b/src/compiler/crystal/tools/formatter.cr index b98cb12acb0f..c769d90c0152 100644 --- a/src/compiler/crystal/tools/formatter.cr +++ b/src/compiler/crystal/tools/formatter.cr @@ -2555,7 +2555,9 @@ module Crystal return false end + @lexer.wants_def_or_macro_name = true next_token + @lexer.wants_def_or_macro_name = false skip_space if (@token.type == :NEWLINE) || @wrote_newline base_indent = @indent + 2 @@ -2973,8 +2975,10 @@ module Crystal write " " if needs_space write_token :"&" skip_space_or_newline - write_token :"." - skip_space_or_newline + write :"." + @lexer.wants_def_or_macro_name = true + next_token_skip_space_or_newline + @lexer.wants_def_or_macro_name = false body = node.body case body