diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr index 5d80b28ed20b..3185fdee6fdc 100644 --- a/src/compiler/crystal/syntax/parser.cr +++ b/src/compiler/crystal/syntax/parser.cr @@ -627,7 +627,7 @@ module Crystal def parse_prefix name_location = @token.location case token_type = @token.type - when .op_bang?, .op_plus?, .op_minus?, .op_tilde?, .op_amp_plus?, .op_amp_minus? + when .unary_operator? location = @token.location next_token_skip_space_or_newline check_void_expression_keyword diff --git a/src/compiler/crystal/syntax/to_s.cr b/src/compiler/crystal/syntax/to_s.cr index 3ea146d15c3e..7735cddb3951 100644 --- a/src/compiler/crystal/syntax/to_s.cr +++ b/src/compiler/crystal/syntax/to_s.cr @@ -332,6 +332,7 @@ module Crystal visit_call node end + # Related: `Token::Kind#unary_operator?` UNARY_OPERATORS = {"+", "-", "~", "&+", "&-"} def visit_call(node, ignore_obj = false) diff --git a/src/compiler/crystal/syntax/token.cr b/src/compiler/crystal/syntax/token.cr index 7b5da2091b67..d26b0a0cb22a 100644 --- a/src/compiler/crystal/syntax/token.cr +++ b/src/compiler/crystal/syntax/token.cr @@ -249,6 +249,13 @@ module Crystal end end + # Returns true if the operator can be used in prefix notation. + # + # Related: `ToSVisitor::UNARY_OPERATORS` + def unary_operator? + self.in?(OP_BANG, OP_PLUS, OP_MINUS, OP_TILDE, OP_AMP_PLUS, OP_AMP_MINUS) + end + def magic? magic_dir? || magic_end_line? || magic_file? || magic_line? end diff --git a/src/compiler/crystal/tools/formatter.cr b/src/compiler/crystal/tools/formatter.cr index f7ebf63be7d2..79d7f3cf5a68 100644 --- a/src/compiler/crystal/tools/formatter.cr +++ b/src/compiler/crystal/tools/formatter.cr @@ -2541,13 +2541,14 @@ module Crystal write_token :OP_COLON_COLON if node.global? if obj - {Token::Kind::OP_BANG, Token::Kind::OP_PLUS, Token::Kind::OP_MINUS, Token::Kind::OP_TILDE, Token::Kind::OP_AMP_PLUS, Token::Kind::OP_AMP_MINUS}.each do |op| - if node.name == op.to_s && @token.type == op && node.args.empty? - write op - next_token_skip_space_or_newline - accept obj - return false - end + # This handles unary operators written in prefix notation. + # The relevant distinction is that the call has a receiver and the + # current token is not that object but a unary operator. + if @token.type.unary_operator? && node.name == @token.type.to_s && node.args.empty? + write @token.type + next_token_skip_space_or_newline + accept obj + return false end accept obj