================
scope resolution
================

Foo::Bar
::Bar

puts ::Foo::Bar

---

(program
  (scope_resolution
    scope: (constant)
    name: (constant))
  (scope_resolution
    name: (constant))
  (call
    method: (identifier)
    arguments: (argument_list
      (scope_resolution
        scope: (scope_resolution
          name: (constant))
        name: (constant)))))

============
element reference
============

foo[bar]
foo[*bar]
foo[* bar]
foo[]

---

(program
  (element_reference object: (identifier) (identifier))
  (element_reference object: (identifier) (splat_argument (identifier)))
  (element_reference object: (identifier) (splat_argument (identifier)))
  (element_reference object: (identifier)))

============
element reference with string
============

foo["bar"]

---

(program (element_reference (identifier) (string (string_content))))

============
element reference with symbol
============

foo[:bar]

---

(program (element_reference (identifier) (simple_symbol)))

============
element assignment
============

foo[bar] = 1

---

(program (assignment
  left: (element_reference
    object: (identifier)
    (identifier))
  right: (integer)))

===============
vacuous literal
===============

()

---

(program (parenthesized_statements))

===============
empty statement
===============

;

---

(program (empty_statement))

===================
yield without value
===================

yield

---

(program (yield))

=====
yield
=====

yield foo
yield foo, bar
yield(baz)

---

(program
  (yield (argument_list (identifier)))
  (yield (argument_list (identifier) (identifier)))
  (yield (argument_list (identifier))))

===
not
===

not foo

---

(program (unary (identifier)))

===
and
===

foo and bar

---

(program (binary (identifier) (identifier)))

===
or
===

foo or bar

---

(program (binary (identifier) (identifier)))

====================
and or associativity
====================

a or b and c

---

(program (binary (binary (identifier) (identifier)) (identifier)))

========
defined?
========

defined? foo
defined? Foo.bar
defined?(foo)
defined?($foo)
defined?(@foo)
defined?(@äö).should be_true

---

(program
  (unary operand: (identifier))
  (unary operand: (call receiver: (constant) method: (identifier)))
  (unary operand: (parenthesized_statements (identifier)))
  (unary operand: (parenthesized_statements (global_variable)))
  (unary operand: (parenthesized_statements (instance_variable)))
  (call
    receiver: (unary operand: (parenthesized_statements (instance_variable)))
    method: (identifier)
    arguments: (argument_list (identifier))))

==========
assignment
==========

x = y
x = *args
FALSE = "false"
TRUE = "true"
NIL = "nil"

---

(program
  (assignment (identifier) (identifier))
  (assignment (identifier) (splat_argument (identifier)))
  (assignment (constant) (string (string_content)))
  (assignment (constant) (string (string_content)))
  (assignment (constant) (string (string_content))))

=====================
multiple assignment
=====================

x, y = [1, 2]
x, * = [1, 2]
x, *args = [1, 2]
x, y = *foo
self.foo, self.bar = target.a?, target.b
(x, y) = foo
(a, b, c = 1)

---

(program
  (assignment (left_assignment_list (identifier) (identifier)) (array (integer) (integer)))
  (assignment (left_assignment_list (identifier) (rest_assignment)) (array (integer) (integer)))
  (assignment (left_assignment_list (identifier) (rest_assignment (identifier))) (array (integer) (integer)))
  (assignment (left_assignment_list (identifier) (identifier)) (splat_argument (identifier)))
  (assignment (left_assignment_list (call (self) (identifier)) (call (self) (identifier))) (right_assignment_list (call (identifier) (identifier)) (call (identifier) (identifier))))
  (assignment (left_assignment_list (destructured_left_assignment (identifier) (identifier))) (identifier))
  (parenthesized_statements (assignment (left_assignment_list (identifier) (identifier) (identifier)) (integer))))

==================================================
multiple assignment with multiple right hand sides
==================================================

foo = 1, 2
x, y = foo, bar

---

(program
  (assignment (identifier) (right_assignment_list (integer) (integer)))
  (assignment
    (left_assignment_list (identifier) (identifier))
    (right_assignment_list (identifier) (identifier))))

==================================================
destructured left hand side assignment
==================================================

a, (b, c), d, (e, (f, g)) = foo

---

(program
  (assignment
    left: (left_assignment_list
      (identifier)
      (destructured_left_assignment (identifier) (identifier))
      (identifier)
      (destructured_left_assignment
        (identifier)
        (destructured_left_assignment (identifier) (identifier))))
    right: (identifier)))

==========
assignment from method call
==========

x = foo a, b
x = foo a, :b => 1, :c => 2

---

(program
  (assignment (identifier)
    (call (identifier)
      (argument_list (identifier) (identifier))))
  (assignment (identifier)
    (call (identifier)
      (argument_list (identifier) (pair (simple_symbol) (integer)) (pair (simple_symbol) (integer))))))

==========
math assignment
==========

x += y
x -= y
x *= y
x **= y
x /= y
puts "/hi"

---

(program
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier))
  (call (identifier) (argument_list (string (string_content)))))

==========
operator assignment
==========

x ||= y
x &&= y
x &= y
x |= y
x %= y
x >>= y
x <<= y
x ^= y

---

(program
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier))
  (operator_assignment (identifier) (identifier)))

===========
conditional
===========

a ? b : c

a ? b
  : c

---

(program
  (conditional
    condition: (identifier)
    consequence: (identifier)
    alternative: (identifier))
  (conditional
    condition: (identifier)
    consequence: (identifier)
    alternative: (identifier)))

===========================================
conditional and character literal ambiguity
===========================================

true ?")":"c"

---
(program (conditional (true) (string (string_content)) (string (string_content))))

===========================================
conditional with reserved identifiers
===========================================

foo ? true: false
foo ? return: false

---

(program
  (conditional (identifier) (true) (false))
  (conditional (identifier) (return) (false)))

===============
inclusive range
===============

a..b

---

(program (range (identifier) (identifier)))

===============
exclusive range
===============

a...b

---

(program (range (identifier) (identifier)))

==========
boolean or
==========

a || b

---

(program (binary (identifier) (identifier)))

===========
boolean and
===========

a && b

---

(program (binary (identifier) (identifier)))

===========
boolean and/or
===========

a || b && c
a && b || c

---

(program
  (binary
    left: (identifier)
    right: (binary
      left: (identifier)
      right: (identifier)))
  (binary
    left: (binary
      left: (identifier)
      right: (identifier))
    right: (identifier)))

==========
relational
==========

a == b
a != b
a === b
a <=> b
a =~ b
a !~ b
a==b
a!=b
a===b
a<=>b
a=~b
a!~b # not a binary operation

---

(program
  (binary left: (identifier) right: (identifier))
  (binary left: (identifier) right: (identifier))
  (binary left: (identifier) right: (identifier))
  (binary left: (identifier) right: (identifier))
  (binary left: (identifier) right: (identifier))
  (binary left: (identifier) right: (identifier))
  (binary left: (identifier) right: (identifier))
  (binary left: (identifier) right: (identifier))
  (binary left: (identifier) right: (identifier))
  (binary left: (identifier) right: (identifier))
  (binary left: (identifier) right: (identifier))
  (call
    method: (identifier)
    arguments: (argument_list
      (unary
        operand: (identifier))))
  (comment))
==========
comparison
==========

a < b
a <= b
a > b
a >= b

---

(program
  (binary (identifier) (identifier))
  (binary (identifier) (identifier))
  (binary (identifier) (identifier))
  (binary (identifier) (identifier)))

==========
bitwise or
==========

a | b

---

(program (binary (identifier) (identifier)))

===========
bitwise xor
===========

a ^ b

---

(program (binary (identifier) (identifier)))

===========
bitwise and
===========

a & b

---

(program (binary (identifier) (identifier)))

=====
shift
=====

a >> b
a << b

---

(program
  (binary (identifier) (identifier))
  (binary (identifier) (identifier)))

========
additive
========

a + b

---

(program (binary (identifier) (identifier)))

==============
multiplicative
==============

a * b
a*b
a *b
a* b

---

(program
  (binary
    left: (identifier)
    right: (identifier))
  (binary
    left: (identifier)
    right: (identifier))
  (call
    method: (identifier)
    arguments: (argument_list
      (splat_argument
        (identifier))))
  (binary
    left: (identifier)
    right: (identifier)))

==============
binary operations
==============

2+2*2

---

(program (binary (integer) (binary (integer) (integer))))

===========
unary minus
===========

-a
foo -a, bar
foo(-a, bar)

---

(program
  (unary (identifier))
  (call (identifier) (argument_list (unary (identifier)) (identifier)))
  (call (identifier) (argument_list (unary (identifier)) (identifier))))

===========
binary minus
===========

foo-a
@ivar-1

---

(program
  (binary (identifier) (identifier))
  (binary (instance_variable) (integer)))

===========
exponential
===========

a ** b

---

(program (binary (identifier) (identifier)))

====
minus, call, exponential, range
====

a - 1
a-1
a -1
a- 1
(-1.foo)

a - b
a-b
a -b
a- b
(-b.foo)

-2**10
-x**10

1..-1
1 .. -1
1.. -1
1 ..-1

---

(program
  (binary
    left: (identifier)
    right: (integer))
  (binary
    left: (identifier)
    right: (integer))
  (call
    method: (identifier)
    arguments: (argument_list
      (unary
        operand: (integer))))
  (binary
    left: (identifier)
    right: (integer))
  (parenthesized_statements
    (call
      receiver: (unary
        operand: (integer))
      method: (identifier)))
  (binary
    left: (identifier)
    right: (identifier))
  (binary
    left: (identifier)
    right: (identifier))
  (call
    method: (identifier)
    arguments: (argument_list
      (unary
        operand: (identifier))))
  (binary
    left: (identifier)
    right: (identifier))
  (parenthesized_statements
    (unary
      operand: (call
        receiver: (identifier)
        method: (identifier))))
  (unary
    operand: (binary
      left: (integer)
      right: (integer)))
  (unary
    operand: (binary
      left: (identifier)
      right: (integer)))
  (range
    begin: (integer)
    end: (unary
      operand: (integer)))
  (range
    begin: (integer)
    end: (unary
      operand: (integer)))
  (range
    begin: (integer)
    end: (unary
      operand: (integer)))
  (range
    begin: (integer)
    end: (unary
      operand: (integer))))

==========
complement
==========

!a

---

(program (unary (identifier)))

===============================
method call
===============================

foo
foo()
print "hello"
print("hello")
exit!
exit!()
include?
include?("hello")
include? "hello"
exit! if done
exit!() if done

---

(program
  (identifier)
  (call
    method: (identifier)
    arguments: (argument_list))
  (call
    method: (identifier)
    arguments: (argument_list (string (string_content))))
  (call
    method: (identifier)
    arguments: (argument_list (string (string_content))))
  (call
    method: (identifier))
  (call
    method: (identifier)
    arguments: (argument_list))
  (call
    method: (identifier))
  (call
    method: (identifier)
    arguments: (argument_list (string (string_content))))
  (call
    method: (identifier)
    arguments: (argument_list (string (string_content))))
  (if_modifier
    body: (call
      method: (identifier))
    condition: (identifier))
  (if_modifier
    body: (call
      method: (identifier)
      arguments: (argument_list))
    condition: (identifier)))

====================================
nested unparenthesized method calls
====================================

puts get_name self, true
puts(get_name self, true)

---

(program
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (self)
          (true)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (self)
          (true))))))

===============================
method call with arguments on multiple lines
===============================

foo a,
  b, c

---

(program
  (call
    method: (identifier)
    arguments: (argument_list (identifier) (identifier) (identifier))))

===============================
method call with trailing comma
===============================

foo(a, b,)
foo(bar(a),)

---

(program
  (call (identifier) (argument_list (identifier) (identifier)))
  (call (identifier) (argument_list (call (identifier) (argument_list (identifier))))))

==============================================
keyword arguments, no space, trailing comma
==============================================

foo(a:b)
foo(a_:b)
foo(a2:b)
foo(a_:b,)
foo(a2:b,)

---

(program
  (call (identifier) (argument_list (pair (hash_key_symbol) (identifier))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (identifier))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (identifier))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (identifier))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (identifier)))))

===============================
method call with receiver
===============================

foo.bar
foo.bar()
foo.bar "hi"
foo.bar "hi", 2
foo.bar("hi")
foo.bar("hi", 2)

---

(program
  (call
    receiver: (identifier)
    method: (identifier))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list (string (string_content))))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list (string (string_content)) (integer)))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list (string (string_content))))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list (string (string_content)) (integer))))

===============================
implicit call
===============================

foo[bar].()
foo.(1, 2)

---

(program
  (call
    receiver: (element_reference object: (identifier) (identifier))
    arguments: (argument_list))
  (call
    receiver: (identifier)
    arguments: (argument_list (integer) (integer))))

===============================
implicit call with block
===============================

a.() {}
a.(b: c) do
  d
end

---

(program
  (call
    receiver: (identifier)
    arguments: (argument_list)
    block: (block))
  (call
    receiver: (identifier)
    arguments: (argument_list (pair key: (hash_key_symbol) value: (identifier)))
    block: (do_block
      body: (body_statement (identifier)))))

===============================
call with operator method name
===============================

foo.[]()

---

(program
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list)))

===============================
method call with :: operator
===============================

foo::bar
::Foo::bar
Foo::Bar::baz

---

(program
  (call (identifier) (identifier))
  (call (scope_resolution (constant)) (identifier))
  (call (scope_resolution (constant) (constant)) (identifier))
)



===============================
method call with safe navigation operator
===============================

foo&.bar

---

(program (call (identifier) (identifier)))

===============================
calls to methods on negated literals
===============================

-1.class.should eq(Fixnum)
-0.1.class

---

(program
  (call
    receiver: (call
      receiver: (unary operand: (integer))
      method: (identifier))
    method: (identifier)
    arguments: (argument_list
  (call
    method: (identifier)
    arguments: (argument_list (constant)))))
  (call
    receiver: (unary operand: (float))
    method: (identifier)))

===============================
method call with hash args
===============================

foo(:a => true)
foo([] => 1)
foo(bar => 1)
foo :a => true, :c => 1

---

(program
  (call (identifier) (argument_list (pair (simple_symbol) (true))))
  (call (identifier) (argument_list (pair (array) (integer))))
  (call (identifier) (argument_list (pair (identifier) (integer))))
  (call (identifier) (argument_list (pair (simple_symbol) (true)) (pair (simple_symbol) (integer)))))

===============================
method call with keyword args
===============================

foo(a: true)
foo a: true
foo B: true
foo a: ;
foo B:

---

(program
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol))))
  (call (identifier) (argument_list (pair (hash_key_symbol))))
)

===============================
method call with reserved keyword args
===============================

foo(if: true)
foo alias: true
foo and: true
foo begin: true
foo break: true
foo case: true
foo class: true
foo def: true
foo defined: true
foo do: true
foo else: true
foo elsif: true
foo end: true
foo ensure: true
foo false: true
foo for: true
foo if: true
foo in: true
foo module: true
foo next: true
foo nil: true
foo not: true
foo or: true
foo redo: true
foo rescue: true
foo retry: true
foo return: true
foo self: true
foo super: true
foo then: true
foo true: true
foo undef: true
foo unless: true
foo until: true
foo when: true
foo while: true
foo yield: true
foo yield:

---

(program
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol) (true))))
  (call (identifier) (argument_list (pair (hash_key_symbol)))))

===============================
method call with paren args
===============================

foo (b), a

---

(program (call (identifier) (argument_list (parenthesized_statements (identifier)) (identifier))))

===============================
method call with block argument
===============================

foo(&:sort)
foo(&bar)
foo(&bar, 1)
foo &bar
foo &bar, 1
foo(&)
foo(&, 1)
foo &;
foo 1, &;

---

(program
  (call (identifier) (argument_list (block_argument (simple_symbol))))
  (call (identifier) (argument_list (block_argument (identifier))))
  (call (identifier) (argument_list (block_argument (identifier)) (integer)))
  (call (identifier) (argument_list (block_argument (identifier))))
  (call (identifier) (argument_list (block_argument (identifier)) (integer)))
  (call (identifier) (argument_list (block_argument)))
  (call (identifier) (argument_list (block_argument) (integer)))
  (call (identifier) (argument_list (block_argument)))
  (call (identifier) (argument_list (integer) (block_argument)))
)

===============================
method call with splat argument
===============================

foo(*bar)
foo *bar
foo *%w{ .. lib }
foo *(bar.baz)

---

(program
  (call (identifier) (argument_list (splat_argument (identifier))))
  (call (identifier) (argument_list (splat_argument (identifier))))
  (call (identifier) (argument_list (splat_argument (string_array (bare_string (string_content)) (bare_string (string_content))))))
  (call (identifier) (argument_list (splat_argument (parenthesized_statements (call (identifier) (identifier)))))))

===============================
method call lambda argument
===============================

foo :bar, -> (a) { 1 }
foo :bar, -> (a) { where(:c => b) }

---

(program
  (call (identifier)
    (argument_list
      (simple_symbol)
      (lambda (lambda_parameters (identifier)) (block (block_body (integer))))))
  (call (identifier)
    (argument_list
      (simple_symbol)
      (lambda
        (lambda_parameters (identifier))
        (block (block_body (call (identifier) (argument_list (pair (simple_symbol) (identifier))))))))))

===============================
method call lambda argument and do block
===============================

foo :bar, -> (a) { 1 } do
end

---

(program
  (call (identifier)
    (argument_list (simple_symbol) (lambda (lambda_parameters (identifier)) (block (block_body (integer)))))
    (do_block)))

===============================================
chained method calls with blocks but no parens
===============================================

a.b c, *d do |e|
  f
end.g h { |i|
  i
}.j do
  k
end

---

(program
  (call
    receiver: (call
      receiver: (identifier)
      method: (identifier)
      arguments: (argument_list
        (identifier)
        (splat_argument (identifier)))
      block: (do_block
        parameters: (block_parameters (identifier))
        body: (body_statement (identifier))))
    method: (identifier)
    arguments: (argument_list
      (call
        receiver: (call
          method: (identifier)
          block: (block
            parameters: (block_parameters (identifier))
            body: (block_body (identifier))))
        method: (identifier)
        block: (do_block
          body: (body_statement (identifier)))))))

===============================
method calls in binary expression
===============================

one two or
  three four, five and
  six seven, eight, nine

---

(program
  (binary
    left: (binary
      left: (call
        method: (identifier)
        arguments: (argument_list (identifier)))
      right: (call
        method: (identifier)
        arguments: (argument_list (identifier) (identifier))))
    right: (call
      method: (identifier)
      arguments: (argument_list (identifier) (identifier) (identifier)))))

===============================
method calls in unary expression
===============================

!a.b c

---

(program
  (unary
    operand: (call
      receiver: (identifier)
      method: (identifier)
      arguments: (argument_list (identifier)))))

===============================
method calls with splat argument
===============================

foo(*bar)
foo(*[bar, baz].quoz)
foo(x, *bar)
foo(*bar.baz)
foo(**baz)
foo **bar, baz
foo(*)
foo(x, *)
foo(**)
foo x, **
---

(program
  (call (identifier) (argument_list (splat_argument (identifier))))
  (call (identifier) (argument_list (splat_argument (call (array (identifier) (identifier)) (identifier)))))
  (call (identifier) (argument_list (identifier) (splat_argument (identifier))))
  (call (identifier) (argument_list (splat_argument (call (identifier) (identifier)))))
  (call (identifier) (argument_list (hash_splat_argument (identifier))))
  (call (identifier) (argument_list (hash_splat_argument (identifier)) (identifier)))
  (call (identifier) (argument_list (splat_argument)))
  (call (identifier) (argument_list (identifier) (splat_argument)))
  (call (identifier) (argument_list (hash_splat_argument)))
  (call (identifier) (argument_list (identifier) (hash_splat_argument))))

============================
method call without parens
============================

include D::E.f

---

(program (call (identifier) (argument_list (call (scope_resolution (constant) (constant)) (identifier)))))

============================
method call with line break
============================

Foo
  .bar
  .baz

Foo \
  .bar

Foo \
  &.bar
  &.baz

Foo
  # a comment
  .bar
  .baz

---

(program
  (call (call (constant) (identifier)) (identifier))
  (call (constant) (identifier))
  (call (call (constant) (identifier)) (identifier))
  (call (call (constant) (comment) (identifier)) (identifier)))

======================================
method call with block argument do end
======================================

foo do |i|
  bar
rescue E
  baz
ensure
  quux
end

foo do
  |i| i
end

foo do; end

foo(a) do |i|
  foo
end

foo.bar a do |i|
  foo
end

foo(a) do |name: i, *args|
end

---

(program
  (call
    method: (identifier)
    block: (do_block
      parameters: (block_parameters (identifier))
    body: (body_statement
      (identifier)
        (rescue
          exceptions: (exceptions (constant))
          body: (then (identifier)))
        (ensure
          (identifier)))))
  (call
    method: (identifier)
    block: (do_block
      parameters: (block_parameters (identifier))
      body: (body_statement (identifier))))
  (call method: (identifier) block: (do_block))
  (call
    method: (identifier)
    arguments: (argument_list (identifier))
    block: (do_block
      parameters: (block_parameters (identifier))
      body: (body_statement (identifier))))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list (identifier))
    block: (do_block
      parameters: (block_parameters (identifier))
      body: (body_statement (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list (identifier))
    block: (do_block
      parameters: (block_parameters
        (keyword_parameter
          name: (identifier)
          value: (identifier))
        (splat_parameter name: (identifier))))))

===============================
method call with block argument curly
===============================

foo { |i| foo }
foo items.any? { |i| i > 0 }
foo(bar, baz) { quux }

---

(program
  (call
    method: (identifier)
    block: (block
      parameters: (block_parameters (identifier))
      body: (block_body (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list (call
      receiver: (identifier)
      method: (identifier)
      block: (block
        parameters: (block_parameters (identifier))
        body: (block_body (binary left: (identifier) right: (integer)))))))
  (call
    method: (identifier)
    arguments: (argument_list (identifier) (identifier))
    block: (block body: (block_body (identifier)))))

===============================
method call with block shadow arguments
===============================

foo { |; i, j| }
foo { |x, y ; i, j| }

---

(program
  (call
    method: (identifier)
    block: (block
      parameters: (block_parameters
        locals: (identifier)
        locals: (identifier))))
  (call
    method: (identifier)
    block: (block
      parameters: (block_parameters
        (identifier)
        (identifier)
        locals: (identifier)
        locals: (identifier)))))


===============================
method call with capitalized name
===============================

request.GET

---

(program (call (identifier) (constant)))

===============================
destructured parameters
===============================

-> (d, *f, (x, y)) {}

def foo(d, *f, (x, y))
end

def foo d, *f, (x, y)
end

foo do |a, (c, d, *f, (x, y)), *e|
end

---

(program
  (lambda
    (lambda_parameters (identifier) (splat_parameter (identifier)) (destructured_parameter (identifier) (identifier)))
    (block))
  (method (identifier)
    (method_parameters (identifier) (splat_parameter (identifier)) (destructured_parameter (identifier) (identifier))))
  (method (identifier)
    (method_parameters (identifier) (splat_parameter (identifier)) (destructured_parameter (identifier) (identifier))))
  (call (identifier) (do_block
    (block_parameters
      (identifier)
      (destructured_parameter (identifier) (identifier) (splat_parameter (identifier)) (destructured_parameter (identifier) (identifier)))
      (splat_parameter (identifier))))))

==================================================
element reference and method with array arguments
==================================================

foo []
foo [1]
foo[1]

---

(program
  (call method: (identifier) arguments: (argument_list (array)))
  (call method: (identifier) arguments: (argument_list (array (integer))))
  (element_reference object: (identifier) (integer)))

=====================================
element reference on call expression
=====================================

d(a) [0]
d.find { |x| x > 1 } [0]
d.find { |x| x > 1 } [0] == 0

---

(program
  (element_reference (call (identifier) (argument_list (identifier))) (integer))
  (element_reference
    (call
      (identifier)
      (identifier)
      (block (block_parameters (identifier)) (block_body (binary (identifier) (integer)))))
    (integer))
  (binary
    (element_reference
      (call
        (identifier)
        (identifier)
        (block (block_parameters (identifier)) (block_body (binary (identifier) (integer)))))
      (integer))
    (integer)))

======================================
call with array and block
======================================

fun [0] { |x| x }

fun [0] do
  puts 1
end

---

(program
  (call
    (identifier)
    (argument_list (array (integer)))
    (block (block_parameters (identifier)) (block_body (identifier))))
  (call
    (identifier)
    (argument_list (array (integer)))
    (do_block
      (body_statement (call (identifier) (argument_list (integer)))))))


========================================================================
call with normal and keyword argument with value that looks like a block
========================================================================
render "foo/bars/show", locals: { }
render "foo/bars/show", locals: { display_text: dt, safe_text: "hello" }

---

(program
  (call (identifier) (argument_list (string (string_content)) (pair (hash_key_symbol) (hash))))
  (call (identifier) (argument_list (string (string_content)) (pair (hash_key_symbol) (hash (pair (hash_key_symbol) (identifier)) (pair (hash_key_symbol) (string (string_content)))))))
)

========================================================================
call with keyword argument on different lines
========================================================================

render :show_details, 5,
    description:
      "Some long " \
      "piece of text.",
    dark_mode: false

render "/foo/bar", params:
    {
        id: 3,
        title: "Hello world"
    },
    headers: { Accept: "text/html" }

render "/foo/bar", params:
    {
        id: 3,
        title: "Hello world"
    }

---

(program
  (call
    method: (identifier)
    arguments: (argument_list
      (simple_symbol)
      (integer)
      (pair
        key: (hash_key_symbol)
        value: (chained_string
          (string
            (string_content))
          (string
            (string_content))))
      (pair
        key: (hash_key_symbol)
        value: (false))))
  (call
    method: (identifier)
    arguments: (argument_list
      (string
        (string_content))
      (pair
        key: (hash_key_symbol)
        value: (hash
          (pair
            key: (hash_key_symbol)
            value: (integer))
          (pair
            key: (hash_key_symbol)
            value: (string
              (string_content)))))
      (pair
        key: (hash_key_symbol)
        value: (hash
          (pair
            key: (hash_key_symbol)
            value: (string
              (string_content)))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (string
        (string_content))
      (pair
        key: (hash_key_symbol)
        value: (hash
          (pair
            key: (hash_key_symbol)
            value: (integer))
          (pair
            key: (hash_key_symbol)
            value: (string
              (string_content))))))))


==============
empty lambda expression
==============

lambda {}

---

(program (call (identifier) (block)))

==================
lambda expressions
==================

lambda { foo }
lambda(&block) { foo }
lambda(&lambda{})

---

(program
  (call (identifier) (block (block_body (identifier))))
  (call (identifier) (argument_list (block_argument (identifier))) (block (block_body (identifier))))
  (call (identifier) (argument_list (block_argument (call (identifier) (block))))))

====================
lambda expression with an arg
====================

lambda { |foo| 1 }

---

(program (call (identifier) (block (block_parameters (identifier)) (block_body (integer)))))

===========================
lambda expression with multiple args
===========================

lambda { |a, b, c|
  1
  2
}

---

(program (call (identifier) (block (block_parameters (identifier) (identifier) (identifier)) (block_body (integer) (integer)))))

===========================
lambda expression with trailing comma
===========================

lambda { |a, b,|
  1
}

---

(program (call (identifier) (block (block_parameters (identifier) (identifier)) (block_body (integer)))))

===========================
lambda expression with optional arg
===========================

lambda { |a, b=nil|
  1
}

---

(program (call (identifier) (block (block_parameters (identifier) (optional_parameter (identifier) (nil))) (block_body (integer)))))

===========================
lambda expression with keyword arg
===========================

lambda { |a, b: nil|
  1
}

---

(program (call
  (identifier)
  (block (block_parameters (identifier) (keyword_parameter (identifier) (nil))) (block_body (integer)))))

====================
lambda expression with do end
====================

lambda do |foo|
  1
end

---

(program (call (identifier) (do_block (block_parameters (identifier)) (body_statement (integer)))))

============================
lambda and proc as variables
============================

proc = Proc.new
lambda = lambda {}
proc = proc {}

---

(program
  (assignment (identifier) (call (constant) (identifier)))
  (assignment (identifier) (call (identifier) (block)))
  (assignment (identifier) (call (identifier) (block))))

===============================
backslash-newline as line continuation
===============================

foo \
  a, b

"abc \
de"

foo \
  "abc"

---

(program
  (call
    (identifier)
    (argument_list (identifier) (identifier)))
  (string (string_content) (escape_sequence) (string_content))
  (call
    (identifier)
    (argument_list (string (string_content)))))

===============================
basic division
===============================

10 / 5

---

(program (binary (integer) (integer)))

===============================
division without spaces
===============================

h/w
"#{foo}"

Time.at(timestamp/1000)
"#{timestamp}"

---

(program
  (binary left: (identifier) right: (identifier))
  (string (interpolation (identifier)))
  (call
    receiver: (constant)
    method: (identifier)
    arguments: (argument_list (binary left: (identifier) right: (integer))))
  (string (interpolation (identifier))))

===============================
regex as parameter
===============================

foo /bar/

---

(program
  (call (identifier) (argument_list (regex (string_content)))))

===============================
regex with opening space
===============================

foo
/ bar/

---

(program (identifier) (regex (string_content)))

===============================
forward slash operator as method
===============================

Foo / "bar"
"/edit"

---

(program (binary (constant) (string (string_content))) (string (string_content)))

===============================
multiline regex
===============================

/ a
  b/

---

(program (regex (string_content)))
