Skip to content

Commit

Permalink
Parser: fix a-b -c incorrectly parsed as a - (b - c)
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite committed Aug 1, 2020
1 parent 7e80d23 commit 665fb7b
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 7 deletions.
12 changes: 12 additions & 0 deletions spec/compiler/parser/parser_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ module Crystal
it_parses "1 / -2", Call.new(1.int32, "/", -2.int32)
it_parses "2 / 3 + 4 / 5", Call.new(Call.new(2.int32, "/", 3.int32), "+", Call.new(4.int32, "/", 5.int32))
it_parses "2 * (3 + 4)", Call.new(2.int32, "*", Expressions.new([Call.new(3.int32, "+", 4.int32)] of ASTNode))
it_parses "a = 1; b = 2; c = 3; a-b-c", Expressions.new([
Assign.new("a".var, 1.int32),
Assign.new("b".var, 2.int32),
Assign.new("c".var, 3.int32),
Call.new(Call.new("a".var, "-", "b".var), "-", "c".var),
])
it_parses "a = 1; b = 2; c = 3; a-b -c", Expressions.new([
Assign.new("a".var, 1.int32),
Assign.new("b".var, 2.int32),
Assign.new("c".var, 3.int32),
Call.new(Call.new("a".var, "-", "b".var), "-", "c".var),
])
it_parses "1/2", Call.new(1.int32, "/", [2.int32] of ASTNode)
it_parses "1 + /foo/", Call.new(1.int32, "+", regex("foo"))
it_parses "1+0", Call.new(1.int32, "+", 0.int32)
Expand Down
27 changes: 20 additions & 7 deletions src/compiler/crystal/syntax/parser.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4056,6 +4056,16 @@ module Crystal

is_var = var?(name)

# If the name is a var and '+' or '-' follow, never treat the name as a call
if is_var && next_comes_plus_or_minus?
var = Var.new(name)
var.doc = doc
var.location = name_location
var.end_location = name_location
next_token
return var
end

@wants_regex = false
next_token

Expand Down Expand Up @@ -4127,13 +4137,6 @@ module Crystal
maybe_var = !force_call && is_var && !has_parentheses
if maybe_var && args.size == 0
Var.new(name)
elsif maybe_var && args.size == 1 && (num = args[0]) && (num.is_a?(NumberLiteral) && num.has_sign?)
sign = num.value[0].to_s
num.value = num.value.byte_slice(1)
Call.new(Var.new(name), sign, args)
elsif maybe_var && args.size == 1 && (arg = args[0]) && arg.is_a?(Call) && !arg.obj.nil? &&
arg.name.in?("+", "-") && (!arg.args || arg.args.size == 0)
Call.new(Var.new(name), arg.name, arg.obj.not_nil!)
else
call = Call.new(nil, name, args, nil, block_arg, named_args, global)
call.name_location = name_location
Expand Down Expand Up @@ -4168,6 +4171,16 @@ module Crystal
node
end

def next_comes_plus_or_minus?
pos = current_pos
while current_char.ascii_whitespace?
next_char_no_column_increment
end
comes_plus_or_mius = current_char == '+' || current_char == '-'
self.current_pos = pos
comes_plus_or_mius
end

def preserve_stop_on_do(new_value = false)
old_stop_on_do = @stop_on_do
@stop_on_do = new_value
Expand Down

0 comments on commit 665fb7b

Please sign in to comment.