================================================================================
plain identifiers
:language(crystal)
================================================================================
fOo
f_0___
🥺
あいうえお
--------------------------------------------------------------------------------

(expressions
  (identifier)
  (identifier)
  (identifier)
  (identifier))

================================================================================
instance and class variables
================================================================================
class Klass
  @a = 87
  @@b = "hjkl"

  def initialize(@a)
    puts @a + 2
  end

  def set_class_var(@@b)
  end
end
--------------------------------------------------------------------------------

(expressions
  (class_def
    name: (constant)
    body: (expressions
      (assign
        lhs: (instance_var)
        rhs: (integer))
      (assign
        lhs: (class_var)
        rhs: (string
          (literal_content)))
      (method_def
        name: (identifier)
        params: (param_list
          (param
            name: (instance_var)))
        body: (expressions
          (call
            method: (identifier)
            arguments: (argument_list
              (call
                receiver: (instance_var)
                method: (operator)
                arguments: (argument_list
                  (integer)))))))
      (method_def
        name: (identifier)
        params: (param_list
          (param
            name: (class_var)))))))

================================================================================
self
:language(crystal)
================================================================================
self
self?
self_
selfself
--------------------------------------------------------------------------------

(expressions
  (self)
  (call
    method: (identifier))
  (identifier)
  (identifier))

================================================================================
pseudo-constants
================================================================================
def pseudo_constants(caller_line = __LINE__, end_of_caller = __END_LINE__)
  puts "Called from line number: #{caller_line}"
  puts "Currently at line number: #{__LINE__}"
  puts "End of caller block is at: #{end_of_caller}"
  puts "File path is: #{__FILE__}"
  puts "Directory file is in: #{__DIR__}"
end
--------------------------------------------------------------------------------

(expressions
  (method_def
    name: (identifier)
    params: (param_list
      (param
        name: (identifier)
        default: (pseudo_constant))
      (param
        name: (identifier)
        default: (pseudo_constant)))
    body: (expressions
      (call
        method: (identifier)
        arguments: (argument_list
          (string
            (literal_content)
            (interpolation
              (identifier)))))
      (call
        method: (identifier)
        arguments: (argument_list
          (string
            (literal_content)
            (interpolation
              (pseudo_constant)))))
      (call
        method: (identifier)
        arguments: (argument_list
          (string
            (literal_content)
            (interpolation
              (identifier)))))
      (call
        method: (identifier)
        arguments: (argument_list
          (string
            (literal_content)
            (interpolation
              (pseudo_constant)))))
      (call
        method: (identifier)
        arguments: (argument_list
          (string
            (literal_content)
            (interpolation
              (pseudo_constant))))))))

================================================================================
nilable constants
:language(crystal)
================================================================================
::Nil???
Foo(String)?
Int32?;

A(B?, C(D?)?)??

if String? <= Comparable(String)?
  # comparable
  if x < Int32 | String
  end
end
--------------------------------------------------------------------------------

(expressions
  (nilable_constant
    (nilable_constant
      (nilable_constant
        (constant))))
  (nilable_constant
    (generic_instance_type
      (constant)
      params: (param_list
        (constant))))
  (nilable_constant
    (constant))
  (nilable_constant
    (nilable_constant
      (generic_instance_type
        (constant)
        params: (param_list
          (nilable_type
            (constant))
          (nilable_type
            (generic_instance_type
              (constant)
              params: (param_list
                (nilable_type
                  (constant)))))))))
  (if
    cond: (call
      receiver: (nilable_constant
        (constant))
      method: (operator)
      arguments: (argument_list
        (nilable_constant
          (generic_instance_type
            (constant)
            params: (param_list
              (constant))))))
    (comment)
    then: (then
      (if
        cond: (call
          receiver: (identifier)
          method: (operator)
          arguments: (argument_list
            (call
              receiver: (constant)
              method: (operator)
              arguments: (argument_list
                (constant)))))))))

================================================================================
special variables
:language(crystal)
================================================================================
$?
$~
$0
$5
$12?
--------------------------------------------------------------------------------

(expressions
  (special_variable)
  (special_variable)
  (special_variable)
  (special_variable)
  (special_variable))

================================================================================
parentheses and expressions
:language(crystal)
================================================================================
()
(((((())))))

((nil; 0) - (1)) + ((2)) + (

(
  3
  +
    (
    4)))
--------------------------------------------------------------------------------

(expressions
  (nil)
  (expressions
    (expressions
      (expressions
        (expressions
          (expressions
            (nil))))))
  (call
    receiver: (call
      receiver: (expressions
        (call
          receiver: (expressions
            (nil)
            (integer))
          method: (operator)
          arguments: (argument_list
            (expressions
              (integer)))))
      method: (operator)
      arguments: (argument_list
        (expressions
          (expressions
            (integer)))))
    method: (operator)
    arguments: (argument_list
      (expressions
        (expressions
          (integer)
          (call
            method: (operator)
            receiver: (expressions
              (integer))))))))

================================================================================
method calls
:language(crystal)
================================================================================
A.b

e()
c?
d!()

true.false?

m1?.m2

puts(b)

a b 7

a!.b!.c!

a b.c

a(b(c()))

pp a # comment
     # comment
  .  # asdf
     # comment
  b  # one more comment
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (constant)
    method: (identifier))
  (call
    method: (identifier)
    arguments: (argument_list))
  (call
    method: (identifier))
  (call
    method: (identifier)
    arguments: (argument_list))
  (call
    receiver: (true)
    method: (identifier))
  (call
    receiver: (call
      method: (identifier))
    method: (identifier))
  (call
    method: (identifier)
    arguments: (argument_list
      (identifier)))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (integer)))))
  (call
    receiver: (call
      receiver: (call
        method: (identifier))
      method: (identifier))
    method: (identifier))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        receiver: (identifier)
        method: (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (call
            method: (identifier)
            arguments: (argument_list))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        receiver: (identifier)
        (comment)
        (comment)
        (comment)
        (comment)
        method: (identifier))))
  (comment))

================================================================================
method calls with multiple arguments
:language(crystal)
================================================================================
puts true, -1, nil

puts false,
  0

puts(true, false, nil)
puts(true, false, nil,)
puts(
  true,
  false,
  nil,
)

puts (), ()
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (true)
      (integer)
      (nil)))
  (call
    method: (identifier)
    arguments: (argument_list
      (false)
      (integer)))
  (call
    method: (identifier)
    arguments: (argument_list
      (true)
      (false)
      (nil)))
  (call
    method: (identifier)
    arguments: (argument_list
      (true)
      (false)
      (nil)))
  (call
    method: (identifier)
    arguments: (argument_list
      (true)
      (false)
      (nil)))
  (call
    method: (identifier)
    arguments: (argument_list
      (nil)
      (nil))))

====================================
Constants can be method names too c:
:language(crystal)
====================================

LibC.PostQueuedCompletionStatus(orig_operation.iocp, 0, 0, lpOverlapped)

---

(expressions
  (call
    receiver: (constant)
    method: (constant)
    arguments: (argument_list
      (call
        receiver: (identifier)
        method: (identifier))
      (integer)
      (integer)
      (identifier))))

================================================================================
splat arguments
:language(crystal)
================================================================================
puts * a
puts *a
puts*a
puts(*a)

pp *a, 2, *{3}

pp(*a+b, *c*d, *e = f)
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    method: (identifier)
    arguments: (argument_list
      (splat
        (identifier))))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    method: (identifier)
    arguments: (argument_list
      (splat
        (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list
      (splat
        (identifier))
      (integer)
      (splat
        (tuple
          (integer)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (splat
        (call
          receiver: (identifier)
          method: (operator)
          arguments: (argument_list
            (identifier))))
      (splat
        (call
          receiver: (identifier)
          method: (operator)
          arguments: (argument_list
            (identifier))))
      (splat
        (assign
          lhs: (identifier)
          rhs: (identifier))))))

================================================================================
double splat arguments
================================================================================
puts ** kwargs
puts **kwargs
puts**kwargs
puts(**kwargs)

pp **{a: 1, "b": 2.0, C: -3, }, **{c: nil}
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    method: (identifier)
    arguments: (argument_list
      (double_splat
        (identifier))))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    method: (identifier)
    arguments: (argument_list
      (double_splat
        (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list
      (double_splat
        (named_tuple
          (named_expr
            name: (identifier)
            (integer))
          (named_expr
            name: (string
              (literal_content))
            (float))
          (named_expr
            name: (identifier)
            (integer))))
      (double_splat
        (named_tuple
          (named_expr
            name: (identifier)
            (nil)))))))

================================================================================
named arguments
================================================================================
foo(named: 1)

bar 1, *splat, a: 2 .. 3, LMNOP: nil, z!: -1, "    \n   ": 'a',  %q(8#{8}): 8

bar 1, c: + 2,
  b:
  3 {

  }
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (named_expr
        name: (identifier)
        (integer))))
  (call
    method: (identifier)
    arguments: (argument_list
      (integer)
      (splat
        (identifier))
      (named_expr
        name: (identifier)
        (range
          begin: (integer)
          operator: (operator)
          end: (integer)))
      (named_expr
        name: (identifier)
        (nil))
      (named_expr
        name: (identifier)
        (integer))
      (named_expr
        name: (string
          (literal_content)
          (escape_sequence)
          (literal_content))
        (char
          (literal_content)))
      (named_expr
        name: (string
          (literal_content))
        (integer))))
  (call
    method: (identifier)
    arguments: (argument_list
      (integer)
      (named_expr
        name: (identifier)
        (call
          method: (operator)
          receiver: (integer)))
      (named_expr
        name: (identifier)
        (integer)))
    block: (block)))

================================================================================
plain assignment
:language(crystal)
================================================================================
a = 1.0

b =
c=
2

d=-0.zero?

(e=1f32)
.to_s
--------------------------------------------------------------------------------

(expressions
  (assign
    lhs: (identifier)
    rhs: (float))
  (assign
    lhs: (identifier)
    rhs: (assign
      lhs: (identifier)
      rhs: (integer)))
  (assign
    lhs: (identifier)
    rhs: (call
      receiver: (integer)
      method: (identifier)))
  (call
    receiver: (expressions
      (assign
        lhs: (identifier)
        rhs: (float)))
    method: (identifier)))

================================================================================
constant assignment
:language(crystal)
================================================================================
A = 1.0

::B =
c=
2

D::E=-0.zero?
--------------------------------------------------------------------------------

(expressions
  (const_assign
    lhs: (constant)
    rhs: (float))
  (const_assign
    lhs: (constant)
    rhs: (assign
      lhs: (identifier)
      rhs: (integer)))
  (const_assign
    lhs: (constant)
    rhs: (call
      receiver: (integer)
      method: (identifier))))

================================================================================
method assignment
================================================================================
::A.b = 1

self
.var =
true

c.foo.bar = d.baz!.quz = 8
--------------------------------------------------------------------------------

(expressions
  (assign
    lhs: (assign_call
      receiver: (constant)
      method: (identifier))
    rhs: (integer))
  (assign
    lhs: (assign_call
      receiver: (self)
      method: (identifier))
    rhs: (true))
  (assign
    lhs: (assign_call
      receiver: (call
        receiver: (identifier)
        method: (identifier))
      method: (identifier))
    rhs: (assign
      lhs: (assign_call
        receiver: (call
          receiver: (identifier)
          method: (identifier))
        method: (identifier))
      rhs: (integer))))

================================================================================
assignment with modifiers
:language(crystal)
================================================================================
a = 5 if c

foo.bar = 0.8 if true if false

baz = 7 unless qux?
--------------------------------------------------------------------------------

(expressions
  (modifier_if
    then: (assign
      lhs: (identifier)
      rhs: (integer))
    cond: (identifier))
  (modifier_if
    then: (modifier_if
      then: (assign
        lhs: (assign_call
          receiver: (identifier)
          method: (identifier))
        rhs: (float))
      cond: (true))
    cond: (false))
  (modifier_unless
    then: (assign
      lhs: (identifier)
      rhs: (integer))
    cond: (call
      method: (identifier))))

================================================================================
multiple assignment
:language(crystal)
================================================================================
foo, bar = baz, fuz

*splat = {1}
* splat = 2, 3, 4

first, _, last = stuff

a, *@b, _ = 1, 2, 3

a, b = c = 1, d = 2

d.val,e.val=:d,:e
a, b, c = d.val, e.val, f = {1, 2, 3}
--------------------------------------------------------------------------------

(expressions
  (assign
    lhs: (identifier)
    lhs: (identifier)
    rhs: (identifier)
    rhs: (identifier))
  (assign
    lhs: (splat
      (identifier))
    rhs: (tuple
      (integer)))
  (assign
    lhs: (splat
      (identifier))
    rhs: (integer)
    rhs: (integer)
    rhs: (integer))
  (assign
    lhs: (identifier)
    lhs: (underscore)
    lhs: (identifier)
    rhs: (identifier))
  (assign
    lhs: (identifier)
    lhs: (splat
      (instance_var))
    lhs: (underscore)
    rhs: (integer)
    rhs: (integer)
    rhs: (integer))
  (assign
    lhs: (identifier)
    lhs: (identifier)
    rhs: (assign
      lhs: (identifier)
      rhs: (integer))
    rhs: (assign
      lhs: (identifier)
      rhs: (integer)))
  (assign
    lhs: (assign_call
      receiver: (identifier)
      method: (identifier))
    lhs: (assign_call
      receiver: (identifier)
      method: (identifier))
    rhs: (symbol
      (literal_content))
    rhs: (symbol
      (literal_content)))
  (assign
    lhs: (identifier)
    lhs: (identifier)
    lhs: (identifier)
    rhs: (call
      receiver: (identifier)
      method: (identifier))
    rhs: (call
      receiver: (identifier)
      method: (identifier))
    rhs: (assign
      lhs: (identifier)
      rhs: (tuple
        (integer)
        (integer)
        (integer)))))

================================================================================
while and until
:language(crystal)
================================================================================
while true; end

while 1
next; end

until a.nil?
  a = 2
  until a
    break
  end
end
--------------------------------------------------------------------------------

(expressions
  (while
    cond: (true))
  (while
    cond: (integer)
    body: (expressions
      (next)))
  (until
    cond: (call
      receiver: (identifier)
      method: (identifier))
    body: (expressions
      (assign
        lhs: (identifier)
        rhs: (integer))
      (until
        cond: (identifier)
        body: (expressions
          (break))))))

================================================================================
basic begin blocks
:language(crystal)
================================================================================
begin 1 end
begin;2;end

begin
  begin
  end
end
begin begin end end

--------------------------------------------------------------------------------

(expressions
  (begin
    body: (expressions
      (integer)))
  (begin
    body: (expressions
      (integer)))
  (begin
    body: (expressions
      (begin)))
  (begin
    body: (expressions
      (begin))))

================================================================================
begin blocks with rescue
:language(crystal)
================================================================================
begin
  1
rescue
  2
end

begin 3; rescue; 4 end

begin
  5; rescue a;
  6; end

begin
  7
rescue Exception; 8
9 rescue c : FooError; 10
end

begin 9
rescue err : FooError | BarError
else
:foo
end

begin
rescue e :
RuntimeError
rescue e:
RuntimeError2
end
--------------------------------------------------------------------------------

(expressions
  (begin
    body: (expressions
      (integer))
    rescue: (rescue
      body: (expressions
        (integer))))
  (begin
    body: (expressions
      (integer))
    rescue: (rescue
      body: (expressions
        (integer))))
  (begin
    body: (expressions
      (integer))
    rescue: (rescue
      variable: (identifier)
      body: (expressions
        (integer))))
  (begin
    body: (expressions
      (integer))
    rescue: (rescue
      type: (constant)
      body: (expressions
        (integer)
        (modifier_rescue
          (integer)
          rescue: (type_declaration
            var: (identifier)
            type: (constant)))
        (integer))))
  (begin
    body: (expressions
      (integer))
    rescue: (rescue
      variable: (identifier)
      type: (union_type
        (constant)
        (constant)))
    else: (else
      body: (expressions
        (symbol
          (literal_content)))))
  (begin
    rescue: (rescue
      variable: (identifier)
      type: (constant))
    rescue: (rescue
      variable: (identifier)
      type: (constant))))

================================================================================
begin blocks with ensure
:language(crystal)
================================================================================
begin
  1
ensure
  2
end

begin a ensure b;ensure c end

puts begin 1
2;3; ensure puts 2;end
--------------------------------------------------------------------------------

(expressions
  (begin
    body: (expressions
      (integer))
    ensure: (ensure
      body: (expressions
        (integer))))
  (begin
    body: (expressions
      (modifier_ensure
        (identifier)
        ensure: (identifier)))
    ensure: (ensure
      body: (expressions
        (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list
      (begin
        body: (expressions
          (integer)
          (integer)
          (integer))
        ensure: (ensure
          body: (expressions
            (call
              method: (identifier)
              arguments: (argument_list
                (integer)))))))))

================================================================================
begin blocks with rescue, else, and ensure
:language(crystal)
================================================================================
begin
1 rescue a : ArgumentError
2
rescue b
3
else
4
ensure
5
end

begin :a; rescue; :b else :c ensure p! :d end
begin :a; rescue; :b else :c; ensure p! :d end
--------------------------------------------------------------------------------

(expressions
  (begin
    body: (expressions
      (modifier_rescue
        (integer)
        rescue: (type_declaration
          var: (identifier)
          type: (constant)))
      (integer))
    rescue: (rescue
      variable: (identifier)
      body: (expressions
        (integer)))
    else: (else
      body: (expressions
        (integer)))
    ensure: (ensure
      body: (expressions
        (integer))))
  (begin
    body: (expressions
      (symbol
        (literal_content)))
    rescue: (rescue
      body: (expressions
        (symbol
          (literal_content))))
    else: (else
      body: (expressions
        (modifier_ensure
          (symbol
            (literal_content))
          ensure: (call
            method: (identifier)
            arguments: (argument_list
              (symbol
                (literal_content))))))))
  (begin
    body: (expressions
      (symbol
        (literal_content)))
    rescue: (rescue
      body: (expressions
        (symbol
          (literal_content))))
    else: (else
      body: (expressions
        (symbol
          (literal_content))))
    ensure: (ensure
      body: (expressions
        (call
          method: (identifier)
          arguments: (argument_list
            (symbol
              (literal_content))))))))

================================================================================
rescue modifiers
:language(crystal)
================================================================================
puts 7 rescue ArgumentError
puts (7 rescue ArgumentError)

do_stuff rescue do_stuff rescue 7
--------------------------------------------------------------------------------

(expressions
  (modifier_rescue
    (call
      method: (identifier)
      arguments: (argument_list
        (integer)))
    rescue: (constant))
  (call
    method: (identifier)
    arguments: (argument_list
      (expressions
        (modifier_rescue
          (integer)
          rescue: (constant)))))
  (modifier_rescue
    (modifier_rescue
      (identifier)
      rescue: (identifier))
    rescue: (integer)))

================================================================================
ensure modifiers
:language(crystal)
================================================================================
puts (4 ensure puts 3)

def foo
  a; b
ensure
  g; h ensure g; h
end
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (expressions
        (modifier_ensure
          (integer)
          ensure: (call
            method: (identifier)
            arguments: (argument_list
              (integer)))))))
  (method_def
    name: (identifier)
    body: (expressions
      (identifier)
      (identifier))
    ensure: (ensure
      body: (expressions
        (identifier)
        (modifier_ensure
          (identifier)
          ensure: (identifier))
        (identifier)))))

================================================================================
binary additive operators
:language(crystal)
================================================================================
1 + 2.0

a &+ b! - C

D &-
  (E)

puts "a" + "b".upcase
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (integer)
    method: (operator)
    arguments: (argument_list
      (float)))
  (call
    receiver: (call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (call
          method: (identifier))))
    method: (operator)
    arguments: (argument_list
      (constant)))
  (call
    receiver: (constant)
    method: (operator)
    arguments: (argument_list
      (expressions
        (constant))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        receiver: (string
          (literal_content))
        method: (operator)
        arguments: (argument_list
          (call
            receiver: (string
              (literal_content))
            method: (identifier)))))))

================================================================================
unary additive operators
:language(crystal)
================================================================================
puts + 2
puts +2
puts+2
puts(+ 2)

puts &+3
puts(&+3)

puts &-3
puts(&-3)

a! - 1
b? -1
c-
1
d_ (- 2)

+-+0
+- 0.3

1-
+2
1-+ 2

- 8u8.to_i8
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    method: (identifier)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (operator)
        receiver: (integer))))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (operator)
        receiver: (integer))))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (operator)
        receiver: (integer))))
  (call
    receiver: (call
      method: (identifier))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    method: (identifier)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    method: (identifier)
    arguments: (argument_list
      (expressions
        (call
          method: (operator)
          receiver: (integer)))))
  (call
    method: (operator)
    receiver: (call
      method: (operator)
      receiver: (integer)))
  (call
    method: (operator)
    receiver: (call
      method: (operator)
      receiver: (float)))
  (call
    receiver: (integer)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (integer)
    method: (operator)
    arguments: (argument_list
      (call
        method: (operator)
        receiver: (integer))))
  (call
    method: (operator)
    receiver: (call
      receiver: (integer)
      method: (identifier))))

================================================================================
multiplicative operators
================================================================================
1 * 2 &* 3.0 / 4.5 // 6 % asdf

pp 2*7..3/1.5

pp 7 +
  4.0 //
    3

pp! // foo
pp! /foo/
(a)/b
d //e
baz/ 7

begin 1 end / 2
foo(// // 3)

/a/ .. /b/ / /c/ .../d/
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (call
      receiver: (call
        receiver: (call
          receiver: (call
            receiver: (integer)
            method: (operator)
            arguments: (argument_list
              (integer)))
          method: (operator)
          arguments: (argument_list
            (float)))
        method: (operator)
        arguments: (argument_list
          (float)))
      method: (operator)
      arguments: (argument_list
        (integer)))
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    method: (identifier)
    arguments: (argument_list
      (range
        begin: (call
          receiver: (integer)
          method: (operator)
          arguments: (argument_list
            (integer)))
        operator: (operator)
        end: (call
          receiver: (integer)
          method: (operator)
          arguments: (argument_list
            (float))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        receiver: (integer)
        method: (operator)
        arguments: (argument_list
          (call
            receiver: (float)
            method: (operator)
            arguments: (argument_list
              (integer)))))))
  (call
    receiver: (call
      method: (identifier))
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    method: (identifier)
    arguments: (argument_list
      (regex
        (literal_content))))
  (call
    receiver: (expressions
      (identifier))
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (begin
      body: (expressions
        (integer)))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        receiver: (regex)
        method: (operator)
        arguments: (argument_list
          (integer)))))
  (range
    begin: (range
      begin: (regex
        (literal_content))
      operator: (operator)
      end: (call
        receiver: (regex
          (literal_content))
        method: (operator)
        arguments: (argument_list
          (regex
            (literal_content)))))
    operator: (operator)
    end: (regex
      (literal_content))))

================================================================================
exponential operators
================================================================================
a ** B &** 7

puts 2 **
10

42.0 % 2 ** EXP
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (call
        receiver: (constant)
        method: (operator)
        arguments: (argument_list
          (integer)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        receiver: (integer)
        method: (operator)
        arguments: (argument_list
          (integer)))))
  (call
    receiver: (float)
    method: (operator)
    arguments: (argument_list
      (call
        receiver: (integer)
        method: (operator)
        arguments: (argument_list
          (constant))))))

================================================================================
shift operators
================================================================================
a << "asdf"
b << c >> D

array << 1 << 2
array << (13 >> 2)
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (string
        (literal_content))))
  (call
    receiver: (call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (identifier)))
    method: (operator)
    arguments: (argument_list
      (constant)))
  (call
    receiver: (call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (expressions
        (call
          receiver: (integer)
          method: (operator)
          arguments: (argument_list
            (integer)))))))

================================================================================
binary/bitwise operators
================================================================================
~1 ^ 5

a ^ b | c

6 & a | 1 << AMT

pp [1, 2, 3] | [4, 5, 6] & [1, 4]
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (call
      method: (operator)
      receiver: (integer))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (identifier)))
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    receiver: (call
      receiver: (integer)
      method: (operator)
      arguments: (argument_list
        (identifier)))
    method: (operator)
    arguments: (argument_list
      (call
        receiver: (integer)
        method: (operator)
        arguments: (argument_list
          (constant)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        receiver: (array
          (integer)
          (integer)
          (integer))
        method: (operator)
        arguments: (argument_list
          (call
            receiver: (array
              (integer)
              (integer)
              (integer))
            method: (operator)
            arguments: (argument_list
              (array
                (integer)
                (integer)))))))))

================================================================================
logical operators
:language(crystal)
================================================================================
!thingy
a.nil? || b
foo && bar

!
true ||
false

a || b && c

d && e || f && g
--------------------------------------------------------------------------------

(expressions
  (not
    (operator)
    (identifier))
  (or
    (call
      receiver: (identifier)
      method: (identifier))
    (operator)
    (identifier))
  (and
    (identifier)
    (operator)
    (identifier))
  (or
    (not
      (operator)
      (true))
    (operator)
    (false))
  (or
    (identifier)
    (operator)
    (and
      (identifier)
      (operator)
      (identifier)))
  (or
    (and
      (identifier)
      (operator)
      (identifier))
    (operator)
    (and
      (identifier)
      (operator)
      (identifier))))

================================================================================
equality operators
================================================================================
a == b

name =~
/Shawn/

c !=\
d

e !~ /regex/

(Symbol === :asdf)
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (regex
        (literal_content))))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (regex
        (literal_content))))
  (expressions
    (call
      receiver: (constant)
      method: (operator)
      arguments: (argument_list
        (symbol
          (literal_content))))))

================================================================================
comparison operators
================================================================================
1 < 2

"b" >
"a"

5 \
<=\
5.1

(9 >= 7)

p! 0 <=> 5
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (integer)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (string
      (literal_content))
    method: (operator)
    arguments: (argument_list
      (string
        (literal_content))))
  (call
    receiver: (integer)
    method: (operator)
    arguments: (argument_list
      (float)))
  (expressions
    (call
      receiver: (integer)
      method: (operator)
      arguments: (argument_list
        (integer))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        receiver: (integer)
        method: (operator)
        arguments: (argument_list
          (integer))))))

================================================================================
chained equality and comparison operators
================================================================================
a <= b <= c

a >= b <= c > d

a == b <= c
a <= b == c
--------------------------------------------------------------------------------

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

================================================================================
combined assignment operators
:language(crystal)
================================================================================
a = 1
a += b
a &+= b
a -= b
a &-= b
a *= b
a &*= b
a /= b
a //= b
a %= b
a |= b
a &= b
a ^= b
a **= b
a <<= b
a >>= b
a ||= b
a &&= b

@c %= 7

ary[0..2] //= val.bar **= 7
--------------------------------------------------------------------------------

(expressions
  (assign
    lhs: (identifier)
    rhs: (integer))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (identifier))
  (op_assign
    lhs: (instance_var)
    (operator)
    rhs: (integer))
  (op_assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (range
          begin: (integer)
          operator: (operator)
          end: (integer))))
    (operator)
    rhs: (op_assign
      lhs: (assign_call
        receiver: (identifier)
        method: (identifier))
      (operator)
      rhs: (integer))))

================================================================================
if/elsif/else
:language(crystal)
================================================================================
if true;end

if ABC
  return 5
end

if cond1
elsif cond2
elsif cond3
else
end

if a "a"; puts "a" elsif b "b"; puts "b" else puts "c" end

if you
  puts "shouldn't"
else if DO
    puts "this"
  end
end
--------------------------------------------------------------------------------

(expressions
  (if
    cond: (true))
  (if
    cond: (constant)
    then: (then
      (return
        (argument_list
          (integer)))))
  (if
    cond: (identifier)
    else: (elsif
      cond: (identifier)
      else: (elsif
        cond: (identifier)
        else: (else))))
  (if
    cond: (call
      method: (identifier)
      arguments: (argument_list
        (string
          (literal_content))))
    then: (then
      (call
        method: (identifier)
        arguments: (argument_list
          (string
            (literal_content)))))
    else: (elsif
      cond: (call
        method: (identifier)
        arguments: (argument_list
          (string
            (literal_content))))
      then: (then
        (call
          method: (identifier)
          arguments: (argument_list
            (string
              (literal_content)))))
      else: (else
        body: (expressions
          (call
            method: (identifier)
            arguments: (argument_list
              (string
                (literal_content))))))))
  (if
    cond: (identifier)
    then: (then
      (call
        method: (identifier)
        arguments: (argument_list
          (string
            (literal_content)))))
    else: (else
      body: (expressions
        (if
          cond: (constant)
          then: (then
            (call
              method: (identifier)
              arguments: (argument_list
                (string
                  (literal_content))))))))))

================================================================================
unless
:language(crystal)
================================================================================
unless a; end

unless true
  pp "asdf"
else
  pp "hjkl"
end
--------------------------------------------------------------------------------

(expressions
  (unless
    cond: (identifier))
  (unless
    cond: (true)
    then: (then
      (call
        method: (identifier)
        arguments: (argument_list
          (string
            (literal_content)))))
    else: (else
      body: (expressions
        (call
          method: (identifier)
          arguments: (argument_list
            (string
              (literal_content))))))))

================================================================================
ternary if
:language(crystal)
================================================================================
thingy? ? 1 : 2.0

puts true ?
"a"
:
# something
'b'

ans = foo ? "foo" : bar ? "bar" : nil
--------------------------------------------------------------------------------

(expressions
  (conditional
    cond: (call
      method: (identifier))
    then: (integer)
    else: (float))
  (call
    method: (identifier)
    arguments: (argument_list
      (conditional
        cond: (true)
        then: (string
          (literal_content))
        (comment)
        else: (char
          (literal_content)))))
  (assign
    lhs: (identifier)
    rhs: (conditional
      cond: (identifier)
      then: (string
        (literal_content))
      else: (conditional
        cond: (identifier)
        then: (string
          (literal_content))
        else: (nil)))))

================================================================================
if modifiers
================================================================================
def foo
  return 7 if foo?
  puts 'c' if bar
  8 if
    if
      true
        "yes"
      else
        "no"
      end

  puts i nil
  puts if? true
  puts iff false

  foo! if bar
  "foo" if bar

  foo if bar
  return if bar
  7 if bar
  foo[0] = 1 if 2
  1 rescue 2 if 3
end
--------------------------------------------------------------------------------

(expressions
  (method_def
    name: (identifier)
    body: (expressions
      (modifier_if
        then: (return
          (argument_list
            (integer)))
        cond: (call
          method: (identifier)))
      (modifier_if
        then: (call
          method: (identifier)
          arguments: (argument_list
            (char
              (literal_content))))
        cond: (identifier))
      (modifier_if
        then: (integer)
        cond: (if
          cond: (true)
          then: (then
            (string
              (literal_content)))
          else: (else
            body: (expressions
              (string
                (literal_content))))))
      (call
        method: (identifier)
        arguments: (argument_list
          (call
            method: (identifier)
            arguments: (argument_list
              (nil)))))
      (call
        method: (identifier)
        arguments: (argument_list
          (call
            method: (identifier)
            arguments: (argument_list
              (true)))))
      (call
        method: (identifier)
        arguments: (argument_list
          (call
            method: (identifier)
            arguments: (argument_list
              (false)))))
      (modifier_if
        then: (call
          method: (identifier))
        cond: (identifier))
      (modifier_if
        then: (string
          (literal_content))
        cond: (identifier))
      (modifier_if
        then: (identifier)
        cond: (identifier))
      (modifier_if
        then: (return)
        cond: (identifier))
      (modifier_if
        then: (integer)
        cond: (identifier))
      (modifier_if
        then: (assign
          lhs: (index_call
            receiver: (identifier)
            method: (operator)
            arguments: (argument_list
              (integer)))
          rhs: (integer))
        cond: (integer))
      (modifier_if
        then: (modifier_rescue
          (integer)
          rescue: (integer))
        cond: (integer)))))

================================================================================
unless modifiers
================================================================================
def foo
  return 7 unless foo?
  puts 'c' unless bar
  8 unless
    unless
      true
        "yes"
      else
        "no"
      end

  puts unles nil
  puts unless? true
  puts unlesss false

  foo! unless bar
  "foo" unless bar

  foo unless bar
  return unless bar
  7 unless bar
  foo[0] = 1 unless 2
  1 rescue 2 unless 3
end
--------------------------------------------------------------------------------

(expressions
  (method_def
    name: (identifier)
    body: (expressions
      (modifier_unless
        then: (return
          (argument_list
            (integer)))
        cond: (call
          method: (identifier)))
      (modifier_unless
        then: (call
          method: (identifier)
          arguments: (argument_list
            (char
              (literal_content))))
        cond: (identifier))
      (modifier_unless
        then: (integer)
        cond: (unless
          cond: (true)
          then: (then
            (string
              (literal_content)))
          else: (else
            body: (expressions
              (string
                (literal_content))))))
      (call
        method: (identifier)
        arguments: (argument_list
          (call
            method: (identifier)
            arguments: (argument_list
              (nil)))))
      (call
        method: (identifier)
        arguments: (argument_list
          (call
            method: (identifier)
            arguments: (argument_list
              (true)))))
      (call
        method: (identifier)
        arguments: (argument_list
          (call
            method: (identifier)
            arguments: (argument_list
              (false)))))
      (modifier_unless
        then: (call
          method: (identifier))
        cond: (identifier))
      (modifier_unless
        then: (string
          (literal_content))
        cond: (identifier))
      (modifier_unless
        then: (identifier)
        cond: (identifier))
      (modifier_unless
        then: (return)
        cond: (identifier))
      (modifier_unless
        then: (integer)
        cond: (identifier))
      (modifier_unless
        then: (assign
          lhs: (index_call
            receiver: (identifier)
            method: (operator)
            arguments: (argument_list
              (integer)))
          rhs: (integer))
        cond: (integer))
      (modifier_unless
        then: (modifier_rescue
          (integer)
          rescue: (integer))
        cond: (integer)))))

================================================================================
calls with do/end blocks
================================================================================
a do end

a b do end

a b() do end

a b c do
d do end; f g do end
end

a (b do 1 end) do 2 end
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    block: (block))
  (call
    method: (identifier)
    arguments: (argument_list
      (identifier))
    block: (block))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list)))
    block: (block))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (identifier))))
    block: (block
      body: (expressions
        (call
          method: (identifier)
          block: (block))
        (call
          method: (identifier)
          arguments: (argument_list
            (identifier))
          block: (block)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (expressions
        (call
          method: (identifier)
          block: (block
            body: (expressions
              (integer))))))
    block: (block
      body: (expressions
        (integer)))))

================================================================================
do/end blocks with rescue, else, and ensure
:language(crystal)
================================================================================
a do rescue e ; end
b do ensure bar end

(1..10).each do |n|
:a
rescue
else
ensure
end
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    block: (block
      rescue: (rescue
        variable: (identifier))))
  (call
    method: (identifier)
    block: (block
      ensure: (ensure
        body: (expressions
          (identifier)))))
  (call
    receiver: (expressions
      (range
        begin: (integer)
        operator: (operator)
        end: (integer)))
    method: (identifier)
    block: (block
      params: (param_list
        (param
          name: (identifier)))
      body: (expressions
        (symbol
          (literal_content)))
      rescue: (rescue)
      else: (else)
      ensure: (ensure))))

================================================================================
calls with {} blocks
================================================================================
a {}
a() {}

a 1 { 2 }
a(1) { 2 }

a { b { c } }

a b c { 1 }
a b c do 1 end

a b { 1 } do 2 end

a {
  b do
    1
  end
}

a do
  b { 2
  } end

a b { 1 } do 2 end

a b { 1 } { 2 }
a(b { 1 }) { 2 }

a 1, {2, b { 4 }} { 3 }
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    block: (block))
  (call
    method: (identifier)
    arguments: (argument_list)
    block: (block))
  (call
    method: (identifier)
    arguments: (argument_list
      (integer))
    block: (block
      body: (expressions
        (integer))))
  (call
    method: (identifier)
    arguments: (argument_list
      (integer))
    block: (block
      body: (expressions
        (integer))))
  (call
    method: (identifier)
    block: (block
      body: (expressions
        (call
          method: (identifier)
          block: (block
            body: (expressions
              (identifier)))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (call
            method: (identifier)
            block: (block
              body: (expressions
                (integer))))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (identifier))))
    block: (block
      body: (expressions
        (integer))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        block: (block
          body: (expressions
            (integer)))))
    block: (block
      body: (expressions
        (integer))))
  (call
    method: (identifier)
    block: (block
      body: (expressions
        (call
          method: (identifier)
          block: (block
            body: (expressions
              (integer)))))))
  (call
    method: (identifier)
    block: (block
      body: (expressions
        (call
          method: (identifier)
          block: (block
            body: (expressions
              (integer)))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        block: (block
          body: (expressions
            (integer)))))
    block: (block
      body: (expressions
        (integer))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        block: (block
          body: (expressions
            (integer)))))
    block: (block
      body: (expressions
        (integer))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        block: (block
          body: (expressions
            (integer)))))
    block: (block
      body: (expressions
        (integer))))
  (call
    method: (identifier)
    arguments: (argument_list
      (integer)
      (tuple
        (integer)
        (call
          method: (identifier)
          block: (block
            body: (expressions
              (integer))))))
    block: (block
      body: (expressions
        (integer)))))

================================================================================
curly brace after a range operator
================================================================================
puts 1, 2 .. { 3 }
puts 4, {a: 5} ... { b: 6 }
puts 1, 2.. { 3 => 4 }

--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (integer)
      (range
        begin: (integer)
        operator: (operator)
        end: (tuple
          (integer)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (integer)
      (range
        begin: (named_tuple
          (named_expr
            name: (identifier)
            (integer)))
        operator: (operator)
        end: (named_tuple
          (named_expr
            name: (identifier)
            (integer))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (integer)
      (range
        begin: (integer)
        operator: (operator)
        end: (hash
          (hash_entry
            (integer)
            (integer)))))))

================================================================================
calls with & block forwarding
================================================================================
foo(&block)
foo &block
a.foo &block
a.foo(&block)
foo "boo", &(->{})
foo "boo", &->{}
foo "boo", &(captured)
bar &foo "hi", "bye"
bar &if true
       foo "yes"
     else
       foo "no"
     end

bar &prc ? 1 : 2 # => bar(&(prc ? 1 : 2))
bar &prc .. 7 # => bar(&(prc..7))

foo &b = a
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (identifier))))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (identifier))))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list
      (string
        (literal_content))
      (block_argument
        (expressions
          (proc
            block: (block))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (string
        (literal_content))
      (block_argument
        (proc
          block: (block)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (string
        (literal_content))
      (block_argument
        (expressions
          (identifier)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (call
          method: (identifier)
          arguments: (argument_list
            (string
              (literal_content))
            (string
              (literal_content)))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (if
          cond: (true)
          then: (then
            (call
              method: (identifier)
              arguments: (argument_list
                (string
                  (literal_content)))))
          else: (else
            body: (expressions
              (call
                method: (identifier)
                arguments: (argument_list
                  (string
                    (literal_content))))))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (conditional
          cond: (identifier)
          then: (integer)
          else: (integer)))))
  (comment)
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (range
          begin: (identifier)
          operator: (operator)
          end: (integer)))))
  (comment)
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (assign
          lhs: (identifier)
          rhs: (identifier))))))

================================================================================
calls with &. short block syntax
================================================================================
method &.  some_method
method(&. to_s)
["i", "o"].join(",", &.upcase(Unicode::CaseOptions::Turkic))
method(&.	[index])
method(&.[](index))
method(&. + 2)
method(&.+(2))
method(&.@ivar)
method(&.take_block(&.foo))
method(&.take_block(&.@foo))
method(&.take_block { |f| f.foo })
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          method: (identifier)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          method: (identifier)))))
  (call
    receiver: (array
      (string
        (literal_content))
      (string
        (literal_content)))
    method: (identifier)
    arguments: (argument_list
      (string
        (literal_content))
      (block_argument
        (implicit_object_call
          method: (identifier)
          arguments: (argument_list
            (constant))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          (index_call
            method: (operator)
            arguments: (argument_list
              (identifier)))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          method: (operator)
          arguments: (argument_list
            (identifier))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          method: (operator)
          arguments: (argument_list
            (integer))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          method: (operator)
          arguments: (argument_list
            (integer))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          (instance_var)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          method: (identifier)
          arguments: (argument_list
            (block_argument
              (implicit_object_call
                method: (identifier))))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          method: (identifier)
          arguments: (argument_list
            (block_argument
              (implicit_object_call
                (instance_var))))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          method: (identifier)
          block: (block
            params: (param_list
              (param
                name: (identifier)))
            body: (expressions
              (call
                receiver: (identifier)
                method: (identifier)))))))))

================================================================================
precedence of block attachment with &. short block syntax
================================================================================
outer method &.take_block do "inner" end
outer method &.take_block { "inner" }
outer(method &.take_block do "inner" end)
outer method(&.take_block) do "inner" end
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (block_argument
            (implicit_object_call
              method: (identifier)
              block: (block
                body: (expressions
                  (string
                    (literal_content))))))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (block_argument
            (implicit_object_call
              method: (identifier)
              block: (block
                body: (expressions
                  (string
                    (literal_content))))))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (block_argument
            (implicit_object_call
              method: (identifier)
              block: (block
                body: (expressions
                  (string
                    (literal_content))))))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier)
        arguments: (argument_list
          (block_argument
            (implicit_object_call
              method: (identifier))))))
    block: (block
      body: (expressions
        (string
          (literal_content))))))

================================================================================
chained &. syntax
================================================================================
reject! &.field.option
find(&.name.==(name))

takes_a_block &.a.b { in_blk }.c do in_blk end . d(nil, &.nil?). [1].@foo

takes_a_block &. a
  .
b (
  arg
)

top 0, &.lvl1 1, &.lvl2 2, &.lvl3 3

# demonstrating block precedence
a &.b c { "in c" }.d.e
a &.b 'b' { "in b" }.d.e
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          receiver: (implicit_object_call
            method: (identifier))
          method: (identifier)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          receiver: (implicit_object_call
            method: (identifier))
          method: (operator)
          arguments: (argument_list
            (identifier))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          receiver: (implicit_object_call
            receiver: (implicit_object_call
              receiver: (implicit_object_call
                receiver: (implicit_object_call
                  receiver: (implicit_object_call
                    method: (identifier))
                  method: (identifier)
                  block: (block
                    body: (expressions
                      (identifier))))
                method: (identifier)
                block: (block
                  body: (expressions
                    (identifier))))
              method: (identifier)
              arguments: (argument_list
                (nil)
                (block_argument
                  (implicit_object_call
                    method: (identifier)))))
            (index_call
              method: (operator)
              arguments: (argument_list
                (integer))))
          (instance_var)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          receiver: (implicit_object_call
            method: (identifier))
          method: (identifier)
          arguments: (argument_list
            (expressions
              (identifier)))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (integer)
      (block_argument
        (implicit_object_call
          method: (identifier)
          arguments: (argument_list
            (integer)
            (block_argument
              (implicit_object_call
                method: (identifier)
                arguments: (argument_list
                  (integer)
                  (block_argument
                    (implicit_object_call
                      method: (identifier)
                      arguments: (argument_list
                        (integer))))))))))))
  (comment)
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          method: (identifier)
          arguments: (argument_list
            (call
              receiver: (call
                receiver: (call
                  method: (identifier)
                  block: (block
                    body: (expressions
                      (string
                        (literal_content)))))
                method: (identifier))
              method: (identifier)))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (implicit_object_call
          receiver: (implicit_object_call
            receiver: (implicit_object_call
              method: (identifier)
              arguments: (argument_list
                (char
                  (literal_content)))
              block: (block
                body: (expressions
                  (string
                    (literal_content)))))
            method: (identifier))
          method: (identifier))))))

================================================================================
ampersand disambiguation
================================================================================
## Operators ##

func &+var   # binary
func(&+var)  # unary
func(&+ var) # unary

func &-var   # binary
func(&-var)  # unary
func(&- var) # unary

func&var     # binary
func&->{}
func & var   # binary
func & ->{}

var.&

## Blocks ##

func(&var)
func &var
func(&->{})
func &->{}

func(&(var.-))
func &(var.-)
func &var.-

func(&(-var))
func &(-var)
--------------------------------------------------------------------------------

(expressions
  (comment)
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (comment)
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (operator)
        receiver: (identifier))))
  (comment)
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (operator)
        receiver: (identifier))))
  (comment)
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (comment)
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (operator)
        receiver: (identifier))))
  (comment)
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (operator)
        receiver: (identifier))))
  (comment)
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (comment)
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (proc
        block: (block))))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (comment)
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (proc
        block: (block))))
  (call
    receiver: (identifier)
    method: (operator))
  (comment)
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (proc
          block: (block)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (proc
          block: (block)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (expressions
          (call
            receiver: (identifier)
            method: (operator))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (expressions
          (call
            receiver: (identifier)
            method: (operator))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (call
          receiver: (identifier)
          method: (operator)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (expressions
          (call
            method: (operator)
            receiver: (identifier))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (block_argument
        (expressions
          (call
            method: (operator)
            receiver: (identifier)))))))

================================================================================
block parameters
:language(crystal)
================================================================================
foo{|_|}

(
  foo(
  ) do |
 _
 |
  end
)

foo { |a, *b, (c, d,),| }
--------------------------------------------------------------------------------

(expressions
  (call
    method: (identifier)
    block: (block
      params: (param_list
        (param
          name: (underscore)))))
  (expressions
    (call
      method: (identifier)
      arguments: (argument_list)
      block: (block
        params: (param_list
          (param
            name: (underscore))))))
  (call
    method: (identifier)
    block: (block
      params: (param_list
        (param
          name: (identifier))
        (splat_param
          name: (identifier))
        (param
          name: (identifier))
        (param
          name: (identifier))))))

================================================================================
nested block parameter unpacking
:language(crystal)
================================================================================
ary = [
  {1, {2, {3, 4}}},
]

ary.each do |(w, (x, (y, z)))|
  w # => 1
  x # => 2
  y # => 3
  z # => 4
end


foo { |a, (w, (*rest1, _, (y, *_, z)), *rest3), c| }
--------------------------------------------------------------------------------

(expressions
  (assign
    lhs: (identifier)
    rhs: (array
      (tuple
        (integer)
        (tuple
          (integer)
          (tuple
            (integer)
            (integer))))))
  (call
    receiver: (identifier)
    method: (identifier)
    block: (block
      params: (param_list
        (param
          name: (identifier))
        (param
          name: (identifier))
        (param
          name: (identifier))
        (param
          name: (identifier)))
      body: (expressions
        (identifier)
        (comment)
        (identifier)
        (comment)
        (identifier)
        (comment)
        (identifier)
        (comment))))
  (call
    method: (identifier)
    block: (block
      params: (param_list
        (param
          name: (identifier))
        (param
          name: (identifier))
        (splat_param
          name: (identifier))
        (param
          name: (underscore))
        (param
          name: (identifier))
        (splat_param
          name: (underscore))
        (param
          name: (identifier))
        (splat_param
          name: (identifier))
        (param
          name: (identifier))))))

================================================================================
yield
================================================================================
def foo; yield; end

def bar
  with yield yield yield
  # called in this order:
  with yield 1 yield :"3", yield("2")

  with a yield! yield *something

  yield &+ yield
end
--------------------------------------------------------------------------------

(expressions
  (method_def
    name: (identifier)
    body: (expressions
      (yield)))
  (method_def
    name: (identifier)
    body: (expressions
      (yield
        with: (yield)
        (argument_list
          (yield)))
      (comment)
      (yield
        with: (yield
          (argument_list
            (integer)))
        (argument_list
          (symbol
            (literal_content))
          (yield
            (argument_list
              (string
                (literal_content))))))
      (yield
        with: (call
          method: (identifier)
          arguments: (argument_list
            (call
              method: (identifier))))
        (argument_list
          (splat
            (identifier))))
      (call
        receiver: (yield)
        method: (operator)
        arguments: (argument_list
          (yield))))))

================================================================================
operator method calls
================================================================================
1.+
1.+ 2

false.|(true)
nil.
!()

a.[](1, 2)
a.[]=(1, 2)
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (integer)
    method: (operator))
  (call
    receiver: (integer)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (false)
    method: (operator)
    arguments: (argument_list
      (true)))
  (call
    receiver: (nil)
    method: (operator)
    arguments: (argument_list))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)
      (integer)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)
      (integer))))

================================================================================
index accessors
:language(crystal)
================================================================================
foo[0]
puts {0} [0]
puts({0} [0]?)

[0, 1, 2].[](-1)

ary[*{0}, **{count: 1}]

a.[count: 1, values: [5]] =0
b.[q: 1, q?: 3, stuff: [5]] =0

a.[2] %= 5
c.[0].[0] += 5

a.[0], *b.[0] = 1, 2, 3

a.[0].setter, a.[1].setter = things

foo[]
foo[][]

foo.[]
foo.[][]
foo[].[]
--------------------------------------------------------------------------------

(expressions
  (index_call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (index_call
    receiver: (call
      method: (identifier)
      block: (block
        body: (expressions
          (integer))))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    method: (identifier)
    arguments: (argument_list
      (index_call
        receiver: (tuple
          (integer))
        method: (operator)
        arguments: (argument_list
          (integer)))))
  (call
    receiver: (array
      (integer)
      (integer)
      (integer))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (index_call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (splat
        (tuple
          (integer)))
      (double_splat
        (named_tuple
          (named_expr
            name: (identifier)
            (integer))))))
  (assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (named_expr
          name: (identifier)
          (integer))
        (named_expr
          name: (identifier)
          (array
            (integer)))))
    rhs: (integer))
  (assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (named_expr
          name: (identifier)
          (integer))
        (named_expr
          name: (identifier)
          (integer))
        (named_expr
          name: (identifier)
          (array
            (integer)))))
    rhs: (integer))
  (op_assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    (operator)
    rhs: (integer))
  (op_assign
    lhs: (index_call
      receiver: (index_call
        receiver: (identifier)
        method: (operator)
        arguments: (argument_list
          (integer)))
      method: (operator)
      arguments: (argument_list
        (integer)))
    (operator)
    rhs: (integer))
  (assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    lhs: (splat
      (index_call
        receiver: (identifier)
        method: (operator)
        arguments: (argument_list
          (integer))))
    rhs: (integer)
    rhs: (integer)
    rhs: (integer))
  (assign
    lhs: (assign_call
      receiver: (index_call
        receiver: (identifier)
        method: (operator)
        arguments: (argument_list
          (integer)))
      method: (identifier))
    lhs: (assign_call
      receiver: (index_call
        receiver: (identifier)
        method: (operator)
        arguments: (argument_list
          (integer)))
      method: (identifier))
    rhs: (identifier))
  (index_call
    receiver: (identifier)
    method: (operator))
  (index_call
    receiver: (index_call
      receiver: (identifier)
      method: (operator))
    method: (operator))
  (call
    receiver: (identifier)
    method: (operator))
  (index_call
    receiver: (call
      receiver: (identifier)
      method: (operator))
    method: (operator))
  (call
    receiver: (index_call
      receiver: (identifier)
      method: (operator))
    method: (operator)))

================================================================================
index assignment
:language(crystal)
================================================================================
a.[]=(1, 2)

a[1] = 2

a[0], a[2, 3] = a[2], a[0]

a[1], *b[0] = a
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)
      (integer)))
  (assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    rhs: (integer))
  (assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)
        (integer)))
    rhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    rhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer))))
  (assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    lhs: (splat
      (index_call
        receiver: (identifier)
        method: (operator)
        arguments: (argument_list
          (integer))))
    rhs: (identifier)))

================================================================================
case expressions
================================================================================
a = case "foo"
    when /o/, /z/
      puts "asdf"
      1
    when .empty?
    when false then ":("
    else
      2
    end

case 1 when 2,
3; else end

case exp
when value1, .value2?(foo: :bar, %( baz ): 'q')  then do_something
when .ljust 5, 'a' do |xyz| 9 end then do_something_else
else                                   do_another_thing
end

case {val1, val2, val3}
when {.even?, .odd?, _}
  true
when {.odd?, .even?, 1}, {_, _ab, .zero?(0) {0}}
  false
else
  case val3
  when .>(0), false
  when .[] 2, count: 3
  when .try(&->(v : Int32){v == 0})
  end
end
--------------------------------------------------------------------------------

(expressions
  (assign
    lhs: (identifier)
    rhs: (case
      cond: (string
        (literal_content))
      (when
        cond: (regex
          (literal_content))
        cond: (regex
          (literal_content))
        body: (expressions
          (call
            method: (identifier)
            arguments: (argument_list
              (string
                (literal_content))))
          (integer)))
      (when
        cond: (implicit_object_call
          method: (identifier)))
      (when
        cond: (false)
        body: (expressions
          (string
            (literal_content))))
      (else
        body: (expressions
          (integer)))))
  (case
    cond: (integer)
    (when
      cond: (integer)
      cond: (integer))
    (else))
  (case
    cond: (identifier)
    (when
      cond: (identifier)
      cond: (implicit_object_call
        method: (identifier)
        arguments: (argument_list
          (named_expr
            name: (identifier)
            (symbol
              (literal_content)))
          (named_expr
            name: (string
              (literal_content))
            (char
              (literal_content)))))
      body: (expressions
        (identifier)))
    (when
      cond: (implicit_object_call
        method: (identifier)
        arguments: (argument_list
          (integer)
          (char
            (literal_content)))
        block: (block
          params: (param_list
            (param
              name: (identifier)))
          body: (expressions
            (integer))))
      body: (expressions
        (identifier)))
    (else
      body: (expressions
        (identifier))))
  (case
    cond: (tuple
      (identifier)
      (identifier)
      (identifier))
    (when
      cond: (tuple
        (implicit_object_call
          method: (identifier))
        (implicit_object_call
          method: (identifier))
        (underscore))
      body: (expressions
        (true)))
    (when
      cond: (tuple
        (implicit_object_call
          method: (identifier))
        (implicit_object_call
          method: (identifier))
        (integer))
      cond: (tuple
        (underscore)
        (identifier)
        (implicit_object_call
          method: (identifier)
          arguments: (argument_list
            (integer))
          block: (block
            body: (expressions
              (integer)))))
      body: (expressions
        (false)))
    (else
      body: (expressions
        (case
          cond: (identifier)
          (when
            cond: (implicit_object_call
              method: (operator)
              arguments: (argument_list
                (integer)))
            cond: (false))
          (when
            cond: (implicit_object_call
              method: (operator)
              arguments: (argument_list
                (integer)
                (named_expr
                  name: (identifier)
                  (integer)))))
          (when
            cond: (implicit_object_call
              method: (identifier)
              arguments: (argument_list
                (block_argument
                  (proc
                    params: (param_list
                      (param
                        name: (identifier)
                        type: (constant)))
                    block: (block
                      body: (expressions
                        (call
                          receiver: (identifier)
                          method: (operator)
                          arguments: (argument_list
                            (integer)))))))))))))))

================================================================================
exhaustive case expressions
:language(crystal)
================================================================================
case nil
in nil
end

case foo
in false
  case bar
  in .bar?
  in Int32
  end
in true, Foo
in .zero? then 0
in Proc(Int32, -> (Int32))
end
--------------------------------------------------------------------------------

(expressions
  (case
    cond: (nil)
    (in
      cond: (nil)))
  (case
    cond: (identifier)
    (in
      cond: (false)
      body: (expressions
        (case
          cond: (identifier)
          (in
            cond: (implicit_object_call
              method: (identifier)))
          (in
            cond: (constant)))))
    (in
      cond: (true)
      cond: (constant))
    (in
      cond: (implicit_object_call
        method: (identifier))
      body: (expressions
        (integer)))
    (in
      cond: (generic_instance_type
        (constant)
        params: (param_list
          (constant)
          (proc_type
            return: (constant)))))))

======================
case without condition
:language(crystal)
======================

case
when true
  puts "world"
end

---

(expressions
  (case
    (when
      cond: (true)
      body: (expressions
        (call
          method: (identifier)
          arguments: (argument_list
            (string
              (literal_content))))))))

============================================
exhaustive case expression with typed tuples
============================================

case {value, this_value}
in {String, String}
	puts "hello"
in {Int32, false}
	puts "world"
end

---

(expressions
  (case
    (tuple
      (identifier)
      (identifier))
    (in
      (tuple
        (constant)
        (constant))
      (expressions
        (call
          (identifier)
          (argument_list
            (string
              (literal_content))))))
    (in
      (tuple
        (constant)
        (false))
      (expressions
        (call
          (identifier)
          (argument_list
            (string
              (literal_content))))))))

===========================================
enums with restrictions and namespaced name
:language(crystal)
===========================================

enum Foo::Bar : UInt8
  STORED   = 0
  DEFLATED = 8
end

---

(expressions
  (enum_def
    name: (constant)
    type: (constant)
    body: (expressions
      (const_assign
        lhs: (constant)
        rhs: (integer))
      (const_assign
        lhs: (constant)
        rhs: (integer)))))

================
select statement
:language(crystal)
================

select
when channel.receive
  puts "hello"
else
  puts "world"
end

---

(expressions
  (select
    (when
      cond: (call
        receiver: (identifier)
        method: (identifier))
      body: (expressions
        (call
          method: (identifier)
          arguments: (argument_list
            (string
              (literal_content))))))
    (else
      body: (expressions
        (call
          method: (identifier)
          arguments: (argument_list
            (string
              (literal_content))))))))

================================================================================
sizeof, instance_sizeof, offsetof
================================================================================
[
  sizeof(String),
  instance_sizeof(String ->),
  offsetof(Foo(Bar), @a),
  offsetof({Char, String, Int32}, 0x0_2),
  offsetof({Char, String, Int32}, 0),
].sum
--------------------------------------------------------------------------------

(expressions
  (call
    receiver: (array
      (sizeof
        (constant))
      (instance_sizeof
        (proc_type
          (constant)))
      (offsetof
        (generic_instance_type
          (constant)
          params: (param_list
            (constant)))
        (instance_var))
      (offsetof
        (tuple_type
          (constant)
          (constant)
          (constant))
        (integer))
      (offsetof
        (tuple_type
          (constant)
          (constant)
          (constant))
        (integer)))
    method: (identifier)))

================================================================================
type declaration
================================================================================
a : Int32
b : Int32 = 7
c = 7

foo ? a : Int32

foo a:7
foo a : Int32
foo a: Int32

f : Proc(Proc(Nil)) = -> : -> { 1; ->{} }
f : -> ->  = -> : -> { 1; ->{} }

v1: Int32 = (v2: Int32 = 2 ; 1)

v1 : Int32 = ( @[Foo]
a = 7)

d : Range(String, String) = "a" .. "b"

f = g : Int32 = 7

class K
  @var : String
  @@var2 : String = "var2"

  getter asdf : String, hjkl : String = "hjkl"
end
--------------------------------------------------------------------------------

(expressions
  (type_declaration
    var: (identifier)
    type: (constant))
  (type_declaration
    var: (identifier)
    type: (constant)
    value: (integer))
  (assign
    lhs: (identifier)
    rhs: (integer))
  (conditional
    cond: (identifier)
    then: (identifier)
    else: (constant))
  (call
    method: (identifier)
    arguments: (argument_list
      (named_expr
        name: (identifier)
        (integer))))
  (call
    method: (identifier)
    arguments: (argument_list
      (type_declaration
        var: (identifier)
        type: (constant))))
  (call
    method: (identifier)
    arguments: (argument_list
      (named_expr
        name: (identifier)
        (constant))))
  (type_declaration
    var: (identifier)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (generic_instance_type
          (constant)
          params: (param_list
            (constant)))))
    value: (proc
      type: (proc_type)
      block: (block
        body: (expressions
          (integer)
          (proc
            block: (block))))))
  (type_declaration
    var: (identifier)
    type: (proc_type
      return: (proc_type))
    value: (proc
      type: (proc_type)
      block: (block
        body: (expressions
          (integer)
          (proc
            block: (block))))))
  (type_declaration
    var: (identifier)
    type: (constant)
    value: (expressions
      (type_declaration
        var: (identifier)
        type: (constant)
        value: (integer))
      (integer)))
  (type_declaration
    var: (identifier)
    type: (constant)
    value: (expressions
      (annotation
        (constant))
      (assign
        lhs: (identifier)
        rhs: (integer))))
  (type_declaration
    var: (identifier)
    type: (generic_instance_type
      (constant)
      params: (param_list
        (constant)
        (constant)))
    value: (range
      begin: (string
        (literal_content))
      operator: (operator)
      end: (string
        (literal_content))))
  (assign
    lhs: (identifier)
    rhs: (type_declaration
      var: (identifier)
      type: (constant)
      value: (integer)))
  (class_def
    name: (constant)
    body: (expressions
      (type_declaration
        var: (instance_var)
        type: (constant))
      (type_declaration
        var: (class_var)
        type: (constant)
        value: (string
          (literal_content)))
      (call
        method: (identifier)
        arguments: (argument_list
          (type_declaration
            var: (identifier)
            type: (constant))
          (type_declaration
            var: (identifier)
            type: (constant)
            value: (string
              (literal_content))))))))

========================
type declaration with ?!
========================
hello_there! : String = "meow"
puts hello_there!

a? : Int32
foo ? a? : Int32
---

(expressions
  (type_declaration
    var: (identifier)
    type: (constant)
    value: (string
      (literal_content)))
  (call
    method: (identifier)
    arguments: (argument_list
      (call
        method: (identifier))))
  (type_declaration
    var: (identifier)
    type: (constant))
  (conditional
    cond: (identifier)
    then: (call
      method: (identifier))
    else: (constant)))

=================
read instance var
:language(crystal)
=================

object.@ivar

---

(expressions
  (call
    receiver: (identifier)
    method: (instance_var)))

======================
global method calls
======================

::raise "Error message"

---

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (string
        (literal_content)))))

===============================================
comma-separated and parenthesized return values
===============================================

def hello(a, b)
  return a, b
  return \
1,
2
  return {a, b}, [c, d]
  return 1, 2, 3,
         4, 5, 6,
         7, 8, 9

  return 1 +
  2 ,
  3 +
  4 ,
  method
  .call(
  a ,
  b
  )

  return()
  return(a, b)

  return(
    1, 2, 3,
    4, 5, 6,
  )

  return
  1, 2
end

---

(expressions
  (method_def
    name: (identifier)
    params: (param_list
      (param
        name: (identifier))
      (param
        name: (identifier)))
    body: (expressions
      (return
        (argument_list
          (identifier)
          (identifier)))
      (return
        (argument_list
          (integer)
          (integer)))
      (return
        (argument_list
          (tuple
            (identifier)
            (identifier))
          (array
            (identifier)
            (identifier))))
      (return
        (argument_list
          (integer)
          (integer)
          (integer)
          (integer)
          (integer)
          (integer)
          (integer)
          (integer)
          (integer)))
      (return
        (argument_list
          (call
            receiver: (integer)
            method: (operator)
            arguments: (argument_list
              (integer)))
          (call
            receiver: (integer)
            method: (operator)
            arguments: (argument_list
              (integer)))
          (call
            receiver: (identifier)
            method: (identifier)
            arguments: (argument_list
              (identifier)
              (identifier)))))
      (return
        (argument_list))
      (return
        (argument_list
          (identifier)
          (identifier)))
      (return
        (argument_list
          (integer)
          (integer)
          (integer)
          (integer)
          (integer)
          (integer)))
      (return)
      (integer)
      (ERROR))))

=======================
assign special variable
=======================

def hello
  $~ = $~
  $? = 1
end

---

(expressions
  (method_def
    name: (identifier)
    body: (expressions
      (assign
        lhs: (special_variable)
        rhs: (special_variable))
      (assign
        lhs: (special_variable)
        rhs: (integer)))))

============================================================
asm expressions
============================================================

asm(
  # the assembly template string, following the
  # syntax for LLVM's integrated assembler
  "nop" :
  # output operands
  "=r"(foo), "=r"(bar) :
  # input operands
  "r"(1), "r"(baz) :
  # names of clobbered registers
  "eax", "memory" :
  # optional flags, corresponding to the LLVM IR
  # sideeffect / alignstack / inteldialect / unwind attributes
  "volatile", "alignstack", "intel", "unwind"
)


asm("svc #0" : "={x0}"(ret)
              : "{w8}"(::Syscall::Code::Name), "{x0}"(args[0].var.id)
              : "memory"
              : "volatile")

asm("
  // declare the presence of a conservative FPU to the ASM compiler
  .fpu vfp

  stmdb  sp!, {r0, r4-r11, lr}  // push 1st argument + callee-saved registers
  vstmdb sp!, {d8-d15}          // push FPU registers
  str    sp, [r0, #0]           // current_context.stack_top = sp
  mov    r4, #1                 // current_context.resumable = 1
  str    r4, [r0, #4]

  mov    r4, #0                 // new_context.resumable = 0
  str    r4, [r1, #4]
  ldr    sp, [r1, #0]           // sp = new_context.stack_top
  vldmia sp!, {d8-d15}          // pop FPU registers
  ldmia  sp!, {r0, r4-r11, lr}  // pop 1st argument + callee-saved registers

  // avoid a stack corruption that will confuse the unwinder
  mov    r1, lr
  mov    lr, #0
  mov    pc, r1
  ")

------------------------------------------------------------

(expressions
  (asm
    (comment)
    (comment)
    text: (string
      (literal_content))
    (comment)
    outputs: (asm_operands
      (asm_operand
        constraint: (string
          (literal_content))
        expression: (identifier))
      (asm_operand
        constraint: (string
          (literal_content))
        expression: (identifier)))
    (comment)
    inputs: (asm_operands
      (asm_operand
        constraint: (string
          (literal_content))
        expression: (integer))
      (asm_operand
        constraint: (string
          (literal_content))
        expression: (identifier)))
    (comment)
    clobbers: (asm_clobbers
      (string
        (literal_content))
      (string
        (literal_content)))
    (comment)
    (comment)
    options: (asm_options
      (string
        (literal_content))
      (string
        (literal_content))
      (string
        (literal_content))
      (string
        (literal_content))))
  (asm
    text: (string
      (literal_content))
    outputs: (asm_operands
      (asm_operand
        constraint: (string
          (literal_content))
        expression: (identifier)))
    inputs: (asm_operands
      (asm_operand
        constraint: (string
          (literal_content))
        expression: (constant))
      (asm_operand
        constraint: (string
          (literal_content))
        expression: (call
          receiver: (call
            receiver: (index_call
              receiver: (identifier)
              method: (operator)
              arguments: (argument_list
                (integer)))
            method: (identifier))
          method: (identifier))))
    clobbers: (asm_clobbers
      (string
        (literal_content)))
    options: (asm_options
      (string
        (literal_content))))
  (asm
    text: (string
      (literal_content))))

=======
nop asm
=======

asm("nop" ::::)
asm ("nop")

---

(expressions
  (asm
    text: (string
      (literal_content)))
  (asm
    text: (string
      (literal_content))))

=============
uninitialized
:language(crystal)
=============

uninitialized Int32
a = uninitialized Int32
@b =
uninitialized Int32*

---

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (constant)))
  (assign
    lhs: (identifier)
    rhs: (uninitialized_var
      (constant)))
  (assign
    lhs: (instance_var)
    rhs: (uninitialized_var
      (pointer_type
        (constant)))))

===========
out keyword
===========

@[MyAnnotationIs(out @of_this_world)]
method.call(out _)
method[out hello].to_s
method.call(out @method, &method)

method(foo: out _)
method bar: out @ivar

method out @ivar2 do
  puts "hello"
end
method(out @ivar2) do
  puts "hello"
end

---

(expressions
  (annotation
    (constant)
    arguments: (argument_list
      (out
        (instance_var))))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list
      (out
        (underscore))))
  (call
    receiver: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (out
          (identifier))))
    method: (identifier))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list
      (out
        (instance_var))
      (block_argument
        (identifier))))
  (call
    method: (identifier)
    arguments: (argument_list
      (named_expr
        name: (identifier)
        (out
          (underscore)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (named_expr
        name: (identifier)
        (out
          (instance_var)))))
  (call
    method: (identifier)
    arguments: (argument_list
      (out
        (instance_var)))
    block: (block
      body: (expressions
        (call
          method: (identifier)
          arguments: (argument_list
            (string
              (literal_content)))))))
  (call
    method: (identifier)
    arguments: (argument_list
      (out
        (instance_var)))
    block: (block
      body: (expressions
        (call
          method: (identifier)
          arguments: (argument_list
            (string
              (literal_content))))))))

================
as pseudo method
================

node.as(LibXML::Node*)
as(Int32 | LibXML::Node*)

---

(expressions
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list
      (pointer_type
        (constant))))
  (call
    method: (identifier)
    arguments: (argument_list
      (union_type
        (constant)
        (pointer_type
          (constant))))))

================
as? pseudo method
================

node.as?(LibXML::Node*)
as?(Int32 | LibXML::Node*)

---

(expressions
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list
      (pointer_type
        (constant))))
  (call
    method: (identifier)
    arguments: (argument_list
      (union_type
        (constant)
        (pointer_type
          (constant))))))

===================
is_a? pseudo method
===================

node.is_a?(LibXML::Node*)
is_a?(Int32 | LibXML::Node*)

# ternary
foo.is_a?(Bar?) ? foo.bar : foo

# nilable type
foo.is_a? Bar? ?

---

(expressions
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list
      (pointer_type
        (constant))))
  (call
    method: (identifier)
    arguments: (argument_list
      (union_type
        (constant)
        (pointer_type
          (constant)))))
  (comment)
  (conditional
    cond: (call
      receiver: (identifier)
      method: (identifier)
      arguments: (argument_list
        (nilable_type
          (constant))))
    then: (call
      receiver: (identifier)
      method: (identifier))
    else: (identifier))
  (comment)
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list
      (nilable_type
        (nilable_type
          (constant))))))

==========================
parenless as pseudo method
==========================

as Int32 | String?
node.as LibXML::Node*
method { T.from_www_form(item).as T* }

---

(expressions
  (call
    method: (identifier)
    arguments: (argument_list
      (union_type
        (constant)
        (nilable_type
          (constant)))))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list
      (pointer_type
        (constant))))
  (call
    method: (identifier)
    block: (block
      body: (expressions
        (call
          receiver: (call
            receiver: (constant)
            method: (identifier)
            arguments: (argument_list
              (identifier)))
          method: (identifier)
          arguments: (argument_list
            (pointer_type
              (constant))))))))

======================
chained pseudo methods
======================

1.as(Int32).is_a?(String).to_s

---

(expressions
  (call
    receiver: (call
      receiver: (call
        receiver: (integer)
        method: (identifier)
        arguments: (argument_list
          (constant)))
      method: (identifier)
      arguments: (argument_list
        (constant)))
    method: (identifier)))

====
nil?
====

nil?
a.nil?
a.
nil?(
)

---

(expressions
  (call
    (identifier))
  (call
    (identifier)
    (identifier))
  (call
    (identifier)
    (identifier)))

==============
pseudo methods
:language(crystal)
==============

class ClassName
  def initialize
    self.is_a?(Object)
    self.nil?
    typeof(self, other) # works
    sizeof(self.class) # works
    instance_sizeof(self.class) # works
    pointerof(123)
    offsetof(self.class, 1) # works
    self.as(Object)
    self.as?(Object)
    responds_to?(:method)
    self.!
  end
end

---

(expressions
  (class_def
    name: (constant)
    body: (expressions
      (method_def
        name: (identifier)
        body: (expressions
          (call
            receiver: (self)
            method: (identifier)
            arguments: (argument_list
              (constant)))
          (call
            receiver: (self)
            method: (identifier))
          (typeof
            (self)
            (identifier))
          (comment)
          (sizeof
            (class_type
              (self)))
          (comment)
          (instance_sizeof
            (class_type
              (self)))
          (comment)
          (pointerof
            (integer))
          (offsetof
            (class_type
              (self))
            (integer))
          (comment)
          (call
            receiver: (self)
            method: (identifier)
            arguments: (argument_list
              (constant)))
          (call
            receiver: (self)
            method: (identifier)
            arguments: (argument_list
              (constant)))
          (call
            method: (identifier)
            arguments: (argument_list
              (symbol
                (literal_content))))
          (call
            receiver: (self)
            method: (operator)))))))

=================================
consistency of index method forms
:language(crystal)
=================================
a = [1,2,3]

a[0]
a.[0]
a.[](0)

a[0,1]
a.[0,1]
a.[](0,1)

a[0]?
a.[0]?
a.[]?(0)

a[]
a.[]
a.[]()

a.[]?
a.[]?()

a[start: 0, count: 1]?
a.[count: 1, start: 1]?
a.[]?(count: 1, start: 1)

b = 7
a[0] = 7
a.[0] = 7

b += 7
a[0] += 7
a.[0] += 7

a[0], a.[1] = 7, 7

a = %i[a b c]
a[value: :d] = 0
b, a[1, 2], c = {0, :e, 0}
---

(expressions
  (assign
    lhs: (identifier)
    rhs: (array
      (integer)
      (integer)
      (integer)))
  (index_call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (index_call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (index_call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)
      (integer)))
  (index_call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)
      (integer)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)
      (integer)))
  (index_call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (index_call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (integer)))
  (index_call
    receiver: (identifier)
    method: (operator))
  (call
    receiver: (identifier)
    method: (operator))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list))
  (call
    receiver: (identifier)
    method: (operator))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list))
  (index_call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (named_expr
        name: (identifier)
        (integer))
      (named_expr
        name: (identifier)
        (integer))))
  (index_call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (named_expr
        name: (identifier)
        (integer))
      (named_expr
        name: (identifier)
        (integer))))
  (call
    receiver: (identifier)
    method: (operator)
    arguments: (argument_list
      (named_expr
        name: (identifier)
        (integer))
      (named_expr
        name: (identifier)
        (integer))))
  (assign
    lhs: (identifier)
    rhs: (integer))
  (assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    rhs: (integer))
  (assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    rhs: (integer))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (integer))
  (op_assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    (operator)
    rhs: (integer))
  (op_assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    (operator)
    rhs: (integer))
  (assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)))
    rhs: (integer)
    rhs: (integer))
  (assign
    lhs: (identifier)
    rhs: (array
      (symbol
        (literal_content))
      (symbol
        (literal_content))
      (symbol
        (literal_content))))
  (assign
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (named_expr
          name: (identifier)
          (symbol
            (literal_content)))))
    rhs: (integer))
  (assign
    lhs: (identifier)
    lhs: (index_call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (integer)
        (integer)))
    lhs: (identifier)
    rhs: (tuple
      (integer)
      (symbol
        (literal_content))
      (integer))))

==========================================
regular expressions and operators using /=
:language(crystal)
==========================================
/ /
/=/

begin
/ hi /
end
self / number
if a == / /
  / /
end

def foo
/ /; / /
end

begin
/ /
  / /
end
a = / /
(/ /)
a = /=/

a; if / /; / /; elsif / /; / /; end

a; if / /
    / /
elsif / /
  / /
end
a; unless / /; / /; else; / /; end
a
unless / /
    / /
else
  / /
end
a
while / /; / /; end
a
while / /
    / /
end
[/ /, / /]
{/ / => / /, / / => / /}
{/ /, / /}
begin; / /; end
begin
  / /
end
/\//
/\ /
%r(/)
%r(\/)
%r(\ )
a()/3
a() /3
a.b() /3
def foo(x = / /); end
begin 1 end / 2

b(/= 3 /)
c = 9
c /= 3 / 7

c.b /= 5
c.b 5, /=/

@d = 5
@d /= 3

begin 8 end /2
begin 8 end / 2

a = /= (.*) =/
B = /== (.*) ==/
---

(expressions
  (regex
    (literal_content))
  (regex
    (literal_content))
  (begin
    body: (expressions
      (regex
        (literal_content))))
  (call
    receiver: (self)
    method: (operator)
    arguments: (argument_list
      (identifier)))
  (if
    cond: (call
      receiver: (identifier)
      method: (operator)
      arguments: (argument_list
        (regex
          (literal_content))))
    then: (then
      (regex
        (literal_content))))
  (method_def
    name: (identifier)
    body: (expressions
      (regex
        (literal_content))
      (regex
        (literal_content))))
  (begin
    body: (expressions
      (regex
        (literal_content))
      (regex
        (literal_content))))
  (assign
    lhs: (identifier)
    rhs: (regex
      (literal_content)))
  (expressions
    (regex
      (literal_content)))
  (assign
    lhs: (identifier)
    rhs: (regex
      (literal_content)))
  (identifier)
  (if
    cond: (regex
      (literal_content))
    then: (then
      (regex
        (literal_content)))
    else: (elsif
      cond: (regex
        (literal_content))
      then: (then
        (regex
          (literal_content)))))
  (identifier)
  (if
    cond: (regex
      (literal_content))
    then: (then
      (regex
        (literal_content)))
    else: (elsif
      cond: (regex
        (literal_content))
      then: (then
        (regex
          (literal_content)))))
  (identifier)
  (unless
    cond: (regex
      (literal_content))
    then: (then
      (regex
        (literal_content)))
    else: (else
      body: (expressions
        (regex
          (literal_content)))))
  (identifier)
  (unless
    cond: (regex
      (literal_content))
    then: (then
      (regex
        (literal_content)))
    else: (else
      body: (expressions
        (regex
          (literal_content)))))
  (identifier)
  (while
    cond: (regex
      (literal_content))
    body: (expressions
      (regex
        (literal_content))))
  (identifier)
  (while
    cond: (regex
      (literal_content))
    body: (expressions
      (regex
        (literal_content))))
  (array
    (regex
      (literal_content))
    (regex
      (literal_content)))
  (hash
    (hash_entry
      (regex
        (literal_content))
      (regex
        (literal_content)))
    (hash_entry
      (regex
        (literal_content))
      (regex
        (literal_content))))
  (tuple
    (regex
      (literal_content))
    (regex
      (literal_content)))
  (begin
    body: (expressions
      (regex
        (literal_content))))
  (begin
    body: (expressions
      (regex
        (literal_content))))
  (regex
    (literal_content))
  (regex
    (literal_content))
  (regex
    (literal_content))
  (regex
    (literal_content))
  (regex
    (literal_content))
  (call
    receiver: (call
      method: (identifier)
      arguments: (argument_list))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (call
      method: (identifier)
      arguments: (argument_list))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (call
      receiver: (identifier)
      method: (identifier)
      arguments: (argument_list))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (method_def
    name: (identifier)
    params: (param_list
      (param
        name: (identifier)
        default: (regex
          (literal_content)))))
  (call
    receiver: (begin
      body: (expressions
        (integer)))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    method: (identifier)
    arguments: (argument_list
      (regex
        (literal_content))))
  (assign
    lhs: (identifier)
    rhs: (integer))
  (op_assign
    lhs: (identifier)
    (operator)
    rhs: (call
      receiver: (integer)
      method: (operator)
      arguments: (argument_list
        (integer))))
  (op_assign
    lhs: (assign_call
      receiver: (identifier)
      method: (identifier))
    (operator)
    rhs: (integer))
  (call
    receiver: (identifier)
    method: (identifier)
    arguments: (argument_list
      (integer)
      (regex
        (literal_content))))
  (assign
    lhs: (instance_var)
    rhs: (integer))
  (op_assign
    lhs: (instance_var)
    (operator)
    rhs: (integer))
  (call
    receiver: (begin
      body: (expressions
        (integer)))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (call
    receiver: (begin
      body: (expressions
        (integer)))
    method: (operator)
    arguments: (argument_list
      (integer)))
  (assign
    lhs: (identifier)
    rhs: (regex
      (literal_content)))
  (const_assign
    lhs: (constant)
    rhs: (regex
      (literal_content))))

===========
loc pragmas
===========

#<loc:push>#<loc:"foo.bar",1,10>#<loc:pop>puts "hello world"
#<loc:"",1,2>
#<loc:"",,>

---

(expressions
  (loc_pragma_push)
  (loc_pragma_location)
  (loc_pragma_pop)
  (call
    method: (identifier)
    arguments: (argument_list
      (string
        (literal_content))))
  (loc_pragma_location)
  (loc_pragma_location))
