Skip to content
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

Fix end locations of some Crystal AST nodes #15452

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
7 changes: 5 additions & 2 deletions spec/compiler/parser/parser_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ private def node_source(string, node)
source_between(string, node.location, node.end_location)
end

private def assert_end_location(source, line_number = 1, column_number = source.size, file = __FILE__, line = __LINE__)
it "gets corrects end location for #{source.inspect}", file, line do
private def assert_end_location(source, line_number = 1, column_number = source.size, file = __FILE__, line = __LINE__, *, focus : Bool = false)
it "gets corrects end location for #{source.inspect}", file, line, focus: focus do
string = "#{source}; 1"
parser = Parser.new(string)
node = parser.parse.as(Expressions).expressions[0]
Expand Down Expand Up @@ -2371,6 +2371,9 @@ module Crystal
assert_end_location "1 rescue 2"
assert_end_location "1 ensure 2"
assert_end_location "foo.bar= *baz"
assert_end_location "case :foo; when :bar; 2; end"
assert_end_location %(asm("nop" ::))
assert_end_location "select; when foo; 2; end"

assert_syntax_error %({"a" : 1}), "space not allowed between named argument name and ':'"
assert_syntax_error %({"a": 1, "b" : 2}), "space not allowed between named argument name and ':'"
Expand Down
30 changes: 18 additions & 12 deletions src/compiler/crystal/syntax/parser.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2084,7 +2084,7 @@ module Crystal
pieces = [] of Piece
has_interpolation = false

delimiter_state, has_interpolation, options, token_end_location = consume_delimiter pieces, delimiter_state, has_interpolation
delimiter_state, has_interpolation, options, end_location = consume_delimiter pieces, delimiter_state, has_interpolation

if want_skip_space && delimiter_state.kind.string?
while true
Expand All @@ -2094,7 +2094,7 @@ module Crystal
if passed_backslash_newline && @token.type.delimiter_start? && @token.delimiter_state.kind.string?
next_string_token(delimiter_state)
delimiter_state = @token.delimiter_state
delimiter_state, has_interpolation, options, token_end_location = consume_delimiter pieces, delimiter_state, has_interpolation
delimiter_state, has_interpolation, options, end_location = consume_delimiter pieces, delimiter_state, has_interpolation
else
break
end
Expand Down Expand Up @@ -2122,7 +2122,7 @@ module Crystal
# no special treatment
end

result.end_location = token_end_location
result.end_location = end_location

result
end
Expand All @@ -2149,7 +2149,7 @@ module Crystal

def consume_delimiter(pieces, delimiter_state, has_interpolation)
options = Regex::CompileOptions::None
token_end_location = nil
end_location = nil
while true
case @token.type
when .string?
Expand All @@ -2161,7 +2161,7 @@ module Crystal
if delimiter_state.kind.regex?
options = consume_regex_options
end
token_end_location = token_end_location()
end_location = token_end_location
next_token
break
when .eof?
Expand Down Expand Up @@ -2204,7 +2204,7 @@ module Crystal
end
end

{delimiter_state, has_interpolation, options, token_end_location}
{delimiter_state, has_interpolation, options, end_location}
end

def consume_regex_options
Expand Down Expand Up @@ -2246,19 +2246,19 @@ module Crystal
pieces = [] of Piece
has_interpolation = false

delimiter_state, has_interpolation, options, token_end_location = consume_delimiter pieces, delimiter_state, has_interpolation
delimiter_state, has_interpolation, options, end_location = consume_delimiter pieces, delimiter_state, has_interpolation

if has_interpolation
pieces = combine_interpolation_pieces(pieces, delimiter_state)
node.expressions.concat(pieces)
else
string = combine_pieces(pieces, delimiter_state)
node.expressions.push(StringLiteral.new(string).at(node).at_end(token_end_location))
node.expressions.push(StringLiteral.new(string).at(node).at_end(end_location))
end

node.heredoc_indent = delimiter_state.heredoc_indent

node.end_location = token_end_location
node.end_location = end_location
end

def needs_heredoc_indent_removed?(delimiter_state)
Expand Down Expand Up @@ -2844,17 +2844,19 @@ module Crystal
a_else = parse_expressions
skip_statement_end
check_ident :end
end_location = token_end_location
next_token
break
when Keyword::END
end_location = token_end_location
next_token
break
else
unexpected_token "expecting when, else or end"
end
end

Case.new(cond, whens, a_else, exhaustive.nil? ? false : exhaustive)
Case.new(cond, whens, a_else, exhaustive.nil? ? false : exhaustive).at_end(end_location)
end

def check_valid_exhaustive_expression(exp)
Expand Down Expand Up @@ -2999,20 +3001,22 @@ module Crystal
a_else = parse_expressions
skip_statement_end
check_ident :end
end_location = token_end_location
next_token
break
when Keyword::END
if whens.empty?
unexpected_token "expecting when, else or end"
end
end_location = token_end_location
next_token
break
else
unexpected_token "expecting when, else or end"
end
end

Select.new(whens, a_else)
Select.new(whens, a_else).at_end(end_location)
end

def valid_select_when?(node)
Expand Down Expand Up @@ -5498,9 +5502,11 @@ module Crystal

check :OP_RPAREN

end_location = token_end_location

next_token_skip_space

Asm.new(text, outputs, inputs, clobbers, volatile, alignstack, intel, can_throw)
Asm.new(text, outputs, inputs, clobbers, volatile, alignstack, intel, can_throw).at_end(end_location)
end

def parse_asm_operands
Expand Down
Loading