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

Foo::bar
::Bar

puts ::Foo::Bar

---

(program
  (scope_resolution
    scope: (constant)
    name: (identifier))
  (scope_resolution
    name: (constant))
  (method_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)))

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

foo[:bar]

---

(program (element_reference (identifier) (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 (identifier))
  (unary (call (constant) (identifier)))
  (unary (parenthesized_statements (identifier)))
  (unary (parenthesized_statements (global_variable)))
  (unary (parenthesized_statements (instance_variable)))
  (method_call
    (call
      (unary (parenthesized_statements (instance_variable)))
      (identifier))
    (argument_list (identifier))))

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

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

---

(program
  (assignment (identifier) (identifier))
  (assignment (identifier) (splat_argument (identifier)))
  (assignment (false) (string))
  (assignment (true) (string))
  (assignment (nil) (string)))

=====================
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)
    (method_call (identifier)
      (argument_list (identifier) (identifier))))
  (assignment (identifier)
    (method_call (identifier)
      (argument_list (identifier) (pair (symbol) (integer)) (pair (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))
  (method_call (identifier) (argument_list (string))))

==========
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)))

===========================================
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)))

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

a == b
a != b
a === b
a <=> b
a =~ b
a !~ b

---

(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)))

==========
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

---

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

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

2+2*2

---

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

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

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

---

(program
  (unary (identifier))
  (method_call (identifier) (argument_list (unary (identifier)) (identifier)))
  (method_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)))

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

!a

---

(program (unary (identifier)))

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

foo
foo()
print "hello"
print("hello")

---

(program
  (identifier)
  (method_call
    method: (identifier)
    arguments: (argument_list))
  (method_call
    method: (identifier)
    arguments: (argument_list (string)))
  (method_call
    method: (identifier)
    arguments: (argument_list (string))))

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

puts get_name self, true

---

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

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

foo a,
  b, c

---

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

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

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

---

(program
  (method_call (identifier) (argument_list (identifier) (identifier)))
  (method_call (identifier) (argument_list (method_call (identifier) (argument_list (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))
  (method_call
    method: (call
      receiver: (identifier)
      method: (identifier))
    arguments: (argument_list))
  (method_call
    method: (call
      receiver: (identifier)
      method: (identifier))
    arguments: (argument_list (string)))
  (method_call
    method: (call
      receiver: (identifier)
      method: (identifier))
    arguments: (argument_list (string) (integer)))
  (method_call
    method: (call
      receiver: (identifier)
      method: (identifier))
    arguments: (argument_list (string)))
  (method_call
    method: (call
      receiver: (identifier)
      method: (identifier))
    arguments: (argument_list (string) (integer))))

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

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

---

(program
  (call (element_reference (identifier) (identifier)) (argument_list))
  (call (identifier) (argument_list (integer) (integer))))

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

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

---

(program
  (method_call
    (call
      (identifier)
      (argument_list))
    (block))
  (method_call
    (call
      (identifier)
      (argument_list (pair (symbol) (identifier))))
    (do_block (identifier))))

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

foo.[]()

---

(program (method_call (call (identifier) (operator)) (argument_list)))

===============================
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
  (method_call
    (call
      (call (unary (integer)) (identifier))
      (identifier))
    (argument_list
      (method_call
        (identifier)
        (argument_list (constant)))))
  (call
    (unary (float))
    (identifier)))

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

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

---

(program
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (array) (integer))))
  (method_call (identifier) (argument_list (pair (identifier) (integer))))
  (method_call (identifier) (argument_list (pair (symbol) (true)) (pair (symbol) (integer)))))

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

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

---

(program
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true)))))

===============================
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

---

(program
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true))))
  (method_call (identifier) (argument_list (pair (symbol) (true)))))

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

foo (b), a

---

(program (method_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

---

(program
  (method_call (identifier) (argument_list (block_argument (symbol))))
  (method_call (identifier) (argument_list (block_argument (identifier))))
  (method_call (identifier) (argument_list (block_argument (identifier)) (integer)))
  (method_call (identifier) (argument_list (block_argument (identifier))))
  (method_call (identifier) (argument_list (block_argument (identifier)) (integer))))

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

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

---

(program
  (method_call (identifier) (argument_list (splat_argument (identifier))))
  (method_call (identifier) (argument_list (splat_argument (identifier))))
  (method_call (identifier) (argument_list (splat_argument (string_array (bare_string) (bare_string)))))
  (method_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
  (method_call (identifier)
    (argument_list
      (symbol)
      (lambda (lambda_parameters (identifier)) (block (integer)))))
  (method_call (identifier)
    (argument_list
      (symbol)
      (lambda
        (lambda_parameters (identifier))
        (block (method_call (identifier) (argument_list (pair (symbol) (identifier)))))))))

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

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

---

(program
  (method_call (identifier)
    (argument_list (symbol) (lambda (lambda_parameters (identifier)) (block (integer))))
    (do_block)))

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

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

---

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

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

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

---

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

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

include D::E.f

---

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

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

Foo
  .bar
  .baz

Foo \
  .bar

---

(program
  (call (call (constant) (identifier)) (identifier))
  (call (constant) (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
  (method_call
    (identifier)
    (do_block
      (block_parameters (identifier))
        (identifier)
      (rescue (exceptions (constant)) (then
        (identifier)))
      (ensure
        (identifier))))
  (method_call
    (identifier)
    (do_block (block_parameters (identifier)) (identifier)))
  (method_call (identifier) (do_block))
  (method_call
    (identifier)
    (argument_list (identifier))
    (do_block (block_parameters (identifier)) (identifier)))
  (method_call
    (call (identifier) (identifier))
    (argument_list (identifier))
    (do_block (block_parameters (identifier)) (identifier)))
  (method_call
    (identifier)
    (argument_list (identifier))
    (do_block (block_parameters (keyword_parameter (identifier) (identifier)) (splat_parameter (identifier))))))

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

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

---

(program
  (method_call (identifier) (block (block_parameters (identifier)) (identifier)))
  (method_call (identifier) (argument_list (method_call
    (call (identifier) (identifier))
    (block (block_parameters (identifier)) (binary (identifier) (integer))))))

  (method_call
    (identifier)
    (argument_list (identifier) (identifier))
    (block (identifier))))

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

foo { |; i, j| }

---

(program (method_call (identifier) (block (block_parameters (identifier) (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))))
  (method_call (identifier) (do_block
    (block_parameters
      (identifier)
      (destructured_parameter (identifier) (identifier) (splat_parameter (identifier)) (destructured_parameter (identifier) (identifier)))
      (splat_parameter (identifier))))))

===============================
method call with array arguments
===============================

foo []
foo [1]
foo[1]

---

(program
  (method_call (identifier) (argument_list (array)))
  (method_call (identifier) (argument_list (array (integer))))
  (element_reference (identifier) (integer)))

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

lambda {}

---

(program (method_call (identifier) (block)))

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

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

---

(program
  (method_call (identifier) (block (identifier)))
  (method_call (identifier) (argument_list (block_argument (identifier))) (block (identifier)))
  (method_call (identifier) (argument_list (block_argument (method_call (identifier) (block))))))

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

lambda { |foo| 1 }

---

(program (method_call (identifier) (block (block_parameters (identifier)) (integer))))

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

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

---

(program (method_call (identifier) (block (block_parameters (identifier) (identifier) (identifier)) (integer) (integer))))

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

lambda { |a, b,|
  1
}

---

(program (method_call (identifier) (block (block_parameters (identifier) (identifier)) (integer))))

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

lambda { |a, b=nil|
  1
}

---

(program (method_call (identifier) (block (block_parameters (identifier) (optional_parameter (identifier) (nil))) (integer))))

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

lambda { |a, b: nil|
  1
}

---

(program (method_call
  (identifier)
  (block (block_parameters (identifier) (keyword_parameter (identifier) (nil))) (integer))))

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

lambda do |foo|
  1
end

---

(program (method_call (identifier) (do_block (block_parameters (identifier)) (integer))))

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

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

---

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

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

foo \
  a, b

"abc \
de"

foo \
  "abc"

---

(program
  (method_call
    (identifier)
    (argument_list (identifier) (identifier)))
  (string (escape_sequence))
  (method_call
    (identifier)
    (argument_list (string))))

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

10 / 5

---

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

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

h/w
"#{foo}"

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

---

(program
  (binary (identifier) (identifier)) (string (interpolation (identifier)))
  (method_call
    (call (constant) (identifier))
    (argument_list (binary (identifier) (integer))))
  (string (interpolation (identifier))))

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

foo /bar/

---

(program
  (method_call (identifier) (argument_list (regex))))

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

foo
/ bar/

---

(program (identifier) (regex))

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

Foo / "bar"
"/edit"

---

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

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

/ a
  b/

---

(program (regex))