================================================================================
Function examples
================================================================================

fn add(x: Int, y: Int) -> Int {
  x + y
}
fn twice(f: fn(t) -> t, x: t) -> t {
  f(f(x))
}
fn inferred_identity(x) {
  x
}
fn replace(
  in string: String,
  each pattern: String,
  with replacement: String
) {
  string.replace(in: string, each: pattern, with: replacement)
}

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

(source_file
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)
        type: (type
          name: (type_identifier)))
      (function_parameter
        name: (identifier)
        type: (type
          name: (type_identifier))))
    return_type: (type
      name: (type_identifier))
    body: (function_body
      (binary_expression
        left: (identifier)
        right: (identifier))))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)
        type: (function_type
          parameter_types: (function_parameter_types
            (type_var))
          return_type: (type_var)))
      (function_parameter
        name: (identifier)
        type: (type_var)))
    return_type: (type_var)
    body: (function_body
      (function_call
        function: (identifier)
        arguments: (arguments
          (argument
            value: (function_call
              function: (identifier)
              arguments: (arguments
                (argument
                  value: (identifier)))))))))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (identifier)))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        label: (label)
        name: (identifier)
        type: (type
          name: (type_identifier)))
      (function_parameter
        label: (label)
        name: (identifier)
        type: (type
          name: (type_identifier)))
      (function_parameter
        label: (label)
        name: (identifier)
        type: (type
          name: (type_identifier))))
    body: (function_body
      (function_call
        function: (field_access
          record: (identifier)
          field: (label))
        arguments: (arguments
          (argument
            label: (label)
            value: (identifier))
          (argument
            label: (label)
            value: (identifier))
          (argument
            label: (label)
            value: (identifier)))))))

================================================================================
Public function examples
================================================================================

pub fn add(x: Int, y: Int) -> Int {
  x + y
}
pub fn twice(f: fn(t) -> t, x: t) -> t {
  f(f(x))
}
pub fn inferred_identity(x) {
  x
}
pub fn replace(
  in string: String,
  each pattern: String,
  with replacement: String
) {
  string.replace(in: in, each: each, with: with)
}

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

(source_file
  (function
    (visibility_modifier)
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)
        type: (type
          name: (type_identifier)))
      (function_parameter
        name: (identifier)
        type: (type
          name: (type_identifier))))
    return_type: (type
      name: (type_identifier))
    body: (function_body
      (binary_expression
        left: (identifier)
        right: (identifier))))
  (function
    (visibility_modifier)
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)
        type: (function_type
          parameter_types: (function_parameter_types
            (type_var))
          return_type: (type_var)))
      (function_parameter
        name: (identifier)
        type: (type_var)))
    return_type: (type_var)
    body: (function_body
      (function_call
        function: (identifier)
        arguments: (arguments
          (argument
            value: (function_call
              function: (identifier)
              arguments: (arguments
                (argument
                  value: (identifier)))))))))
  (function
    (visibility_modifier)
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (identifier)))
  (function
    (visibility_modifier)
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        label: (label)
        name: (identifier)
        type: (type
          name: (type_identifier)))
      (function_parameter
        label: (label)
        name: (identifier)
        type: (type
          name: (type_identifier)))
      (function_parameter
        label: (label)
        name: (identifier)
        type: (type
          name: (type_identifier))))
    body: (function_body
      (function_call
        function: (field_access
          record: (identifier)
          field: (label))
        arguments: (arguments
          (argument
            label: (label)
            value: (identifier))
          (argument
            label: (label)
            value: (identifier))
          (argument
            label: (label)
            value: (identifier)))))))

================================================================================
Basic functions
================================================================================

fn str() {
  "Hello, World!"
}
fn integer() {
  42
}
fn float() {
  12.34
}
fn record() {
  Cat(name: "Nubi")
}
fn remote_record() {
  cats.Cat(name: "Nubi")
}
fn var(x) {
  x
}
fn funcall() {
  myfun()
}
fn unfinished() {
  todo("Finish me!")
}
fn tuple(x) {
  #(x, 1)
}
fn list(x) {
  [1, 2, ..x]
}
fn bit_string() {
  <<0:4, 1:3, 1:1>>
}
fn return_fun(x) {
  fn(y: Int) { x + y }
}
fn expression_group() {
  {
    1 + 1
    "Hello, World!"
  }
}
fn foob(x, y) {
  case x, y {
    1, 2 | 3, 4 -> True
    _else -> False
  }
}
fn assignment() {
  let x = {
    1 + 1
    "Hello, World!"
  }
  let y = x
  let #(x, _) = #(1, 2)
}
fn assertations() {
  assert x = {
    1 + 1
    "Hello, World!"
  }
  assert y = x
  assert #(x, _) = #(1, 2)
}
fn update(x) {
  Cat(..x, name: "Nubi", cuteness: 1000 + 1001)
  animals.Dog(..myfun(), name: "Rey", cuteness: 1950)
}
fn tuple_access(x) {
  x.1
}
fn field_access(x) {
  x.name
}

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

(source_file
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (string
        (quoted_content))))
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (integer)))
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (float)))
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (record
        name: (constructor_name)
        arguments: (arguments
          (argument
            label: (label)
            value: (string
              (quoted_content)))))))
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (record
        name: (remote_constructor_name
          module: (identifier)
          name: (constructor_name))
        arguments: (arguments
          (argument
            label: (label)
            value: (string
              (quoted_content)))))))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (identifier)))
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (function_call
        function: (identifier)
        arguments: (arguments))))
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (todo
        message: (string
          (quoted_content)))))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (tuple
        (identifier)
        (integer))))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (list
        (integer)
        (integer)
        spread: (identifier))))
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (bit_string
        (bit_string_segment
          value: (integer)
          options: (bit_string_segment_options
            (integer)))
        (bit_string_segment
          value: (integer)
          options: (bit_string_segment_options
            (integer)))
        (bit_string_segment
          value: (integer)
          options: (bit_string_segment_options
            (integer))))))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (anonymous_function
        parameters: (function_parameters
          (function_parameter
            name: (identifier)
            type: (type
              name: (type_identifier))))
        body: (function_body
          (binary_expression
            left: (identifier)
            right: (identifier))))))
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (expression_group
        (binary_expression
          left: (integer)
          right: (integer))
        (string
          (quoted_content)))))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier))
      (function_parameter
        name: (identifier)))
    body: (function_body
      (case
        subjects: (case_subjects
          (identifier)
          (identifier))
        clauses: (case_clauses
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (integer)
                (integer))
              (case_clause_pattern
                (integer)
                (integer)))
            value: (record
              name: (constructor_name)))
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (discard)))
            value: (record
              name: (constructor_name)))))))
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (let
        pattern: (identifier)
        value: (expression_group
          (binary_expression
            left: (integer)
            right: (integer))
          (string
            (quoted_content))))
      (let
        pattern: (identifier)
        value: (identifier))
      (let
        pattern: (tuple_pattern
          (identifier)
          (discard))
        value: (tuple
          (integer)
          (integer)))))
  (function
    name: (identifier)
    parameters: (function_parameters)
    body: (function_body
      (assert
        pattern: (identifier)
        value: (expression_group
          (binary_expression
            left: (integer)
            right: (integer))
          (string
            (quoted_content))))
      (assert
        pattern: (identifier)
        value: (identifier))
      (assert
        pattern: (tuple_pattern
          (identifier)
          (discard))
        value: (tuple
          (integer)
          (integer)))))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (record_update
        constructor: (constructor_name)
        spread: (identifier)
        arguments: (record_update_arguments
          (record_update_argument
            label: (label)
            value: (string
              (quoted_content)))
          (record_update_argument
            label: (label)
            value: (binary_expression
              left: (integer)
              right: (integer)))))
      (record_update
        constructor: (remote_constructor_name
          module: (identifier)
          name: (constructor_name))
        spread: (function_call
          function: (identifier)
          arguments: (arguments))
        arguments: (record_update_arguments
          (record_update_argument
            label: (label)
            value: (string
              (quoted_content)))
          (record_update_argument
            label: (label)
            value: (integer))))))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (tuple_access
        tuple: (identifier)
        index: (integer))))
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (field_access
        record: (identifier)
        field: (label)))))

================================================================================
Cases
================================================================================

fn trial(x, y, z) {
  case x {
    1 -> 2
    2 -> 3
    _ -> 4
  }

  case y {
    #(z, _) | #(_, z) if z.1 == 5 -> True
    #(_, z) if z.2 >= 4 < 5 || z.1 > 6 -> True
  }

  case #(x, y) {
    #(1, 2) -> #(3, 4)
    _ -> #(5, 6)
  }

  case z {
    Uri(scheme: Some("https"), ..) -> True
    _ -> False
  }
}

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

(source_file
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier))
      (function_parameter
        name: (identifier))
      (function_parameter
        name: (identifier)))
    body: (function_body
      (case
        subjects: (case_subjects
          (identifier))
        clauses: (case_clauses
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (integer)))
            value: (integer))
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (integer)))
            value: (integer))
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (discard)))
            value: (integer))))
      (case
        subjects: (case_subjects
          (identifier))
        clauses: (case_clauses
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (tuple_pattern
                  (identifier)
                  (discard)))
              (case_clause_pattern
                (tuple_pattern
                  (discard)
                  (identifier))))
            guard: (case_clause_guard
              (binary_expression
                left: (tuple_access
                  tuple: (identifier)
                  index: (integer))
                right: (integer)))
            value: (record
              name: (constructor_name)))
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (tuple_pattern
                  (discard)
                  (identifier))))
            guard: (case_clause_guard
              (binary_expression
                left: (binary_expression
                  left: (binary_expression
                    left: (tuple_access
                      tuple: (identifier)
                      index: (integer))
                    right: (integer))
                  right: (integer))
                right: (binary_expression
                  left: (tuple_access
                    tuple: (identifier)
                    index: (integer))
                  right: (integer))))
            value: (record
              name: (constructor_name)))))
      (case
        subjects: (case_subjects
          (tuple
            (identifier)
            (identifier)))
        clauses: (case_clauses
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (tuple_pattern
                  (integer)
                  (integer))))
            value: (tuple
              (integer)
              (integer)))
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (discard)))
            value: (tuple
              (integer)
              (integer)))))
      (case
        subjects: (case_subjects
          (identifier))
        clauses: (case_clauses
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (record_pattern
                  name: (constructor_name)
                  arguments: (record_pattern_arguments
                    (record_pattern_argument
                      label: (label)
                      pattern: (record_pattern
                        name: (constructor_name)
                        arguments: (record_pattern_arguments
                          (record_pattern_argument
                            pattern: (string
                              (quoted_content))))))
                    (pattern_spread)))))
            value: (record
              name: (constructor_name)))
          (case_clause
            patterns: (case_clause_patterns
              (case_clause_pattern
                (discard)))
            value: (record
              name: (constructor_name))))))))

================================================================================
Try patterns
================================================================================

fn try_try_again(x, y) -> Int {
  try int_x = todo
  try _who_cares = todo
  try file.IODevice() = todo
  try Node = todo
  try "hello" = todo
  try 1 = todo
  try 12.34 = todo
  try #(a, b) = todo
  try <<a:utf8, b:size(8)>> = todo
  try [a, b] = todo
}

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

(source_file
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier))
      (function_parameter
        name: (identifier)))
    return_type: (type
      name: (type_identifier))
    body: (function_body
      (try
        pattern: (identifier)
        value: (todo))
      (try
        pattern: (discard)
        value: (todo))
      (try
        pattern: (record_pattern
          name: (remote_constructor_name
            module: (identifier)
            name: (constructor_name))
          arguments: (record_pattern_arguments))
        value: (todo))
      (try
        pattern: (record_pattern
          name: (constructor_name))
        value: (todo))
      (try
        pattern: (string
          (quoted_content))
        value: (todo))
      (try
        pattern: (integer)
        value: (todo))
      (try
        pattern: (float)
        value: (todo))
      (try
        pattern: (tuple_pattern
          (identifier)
          (identifier))
        value: (todo))
      (try
        pattern: (bit_string_pattern
          (bit_string_segment
            value: (identifier)
            options: (bit_string_segment_options
              (bit_string_segment_option)))
          (bit_string_segment
            value: (identifier)
            options: (bit_string_segment_options
              (bit_string_segment_option
                (integer)))))
        value: (todo))
      (try
        pattern: (list_pattern
          (identifier)
          (identifier))
        value: (todo)))))

================================================================================
Complex binary expressions
================================================================================

fn complicated(x, y) {
  x > y && x >= y || x + y |> fun() < x * y + 1
}

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

(source_file
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier))
      (function_parameter
        name: (identifier)))
    body: (function_body
      (binary_expression
        left: (binary_expression
          left: (binary_expression
            left: (identifier)
            right: (identifier))
          right: (binary_expression
            left: (identifier)
            right: (identifier)))
        right: (binary_expression
          left: (binary_expression
            left: (binary_expression
              left: (identifier)
              right: (identifier))
            right: (function_call
              function: (identifier)
              arguments: (arguments)))
          right: (binary_expression
            left: (binary_expression
              left: (identifier)
              right: (identifier))
            right: (integer)))))))

================================================================================
Complex nesting of field and tuple access
================================================================================

fn complex_data_fun(x, y) {
  y.barbaz.2.thing
  x.1.qux.10
  x.2.foobar.1("Hello", 1)
  y.quux.2.quuz(12.34, "a")
}

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

(source_file
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier))
      (function_parameter
        name: (identifier)))
    body: (function_body
      (field_access
        record: (tuple_access
          tuple: (field_access
            record: (identifier)
            field: (label))
          index: (integer))
        field: (label))
      (tuple_access
        tuple: (field_access
          record: (tuple_access
            tuple: (identifier)
            index: (integer))
          field: (label))
        index: (integer))
      (function_call
        function: (tuple_access
          tuple: (field_access
            record: (tuple_access
              tuple: (identifier)
              index: (integer))
            field: (label))
          index: (integer))
        arguments: (arguments
          (argument
            value: (string
              (quoted_content)))
          (argument
            value: (integer))))
      (function_call
        function: (field_access
          record: (tuple_access
            tuple: (field_access
              record: (identifier)
              field: (label))
            index: (integer))
          field: (label))
        arguments: (arguments
          (argument
            value: (float))
          (argument
            value: (string
              (quoted_content))))))))

================================================================================
Unusual function invocations
================================================================================

fn weird(x) {
  x(name: "Nubi")
  fn (x) { x + 1 }(3)
  {
    let fun = fn (x) { x + 1 }
  }(3)
  case 5 {
    5 -> fn (x) { x + 1 }
  }(3)
  returns_fun(1)(5)
}

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

(source_file
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (function_call
        function: (identifier)
        arguments: (arguments
          (argument
            label: (label)
            value: (string
              (quoted_content)))))
      (function_call
        function: (anonymous_function
          parameters: (function_parameters
            (function_parameter
              name: (identifier)))
          body: (function_body
            (binary_expression
              left: (identifier)
              right: (integer))))
        arguments: (arguments
          (argument
            value: (integer))))
      (function_call
        function: (expression_group
          (let
            pattern: (identifier)
            value: (anonymous_function
              parameters: (function_parameters
                (function_parameter
                  name: (identifier)))
              body: (function_body
                (binary_expression
                  left: (identifier)
                  right: (integer))))))
        arguments: (arguments
          (argument
            value: (integer))))
      (function_call
        function: (case
          subjects: (case_subjects
            (integer))
          clauses: (case_clauses
            (case_clause
              patterns: (case_clause_patterns
                (case_clause_pattern
                  (integer)))
              value: (anonymous_function
                parameters: (function_parameters
                  (function_parameter
                    name: (identifier)))
                body: (function_body
                  (binary_expression
                    left: (identifier)
                    right: (integer)))))))
        arguments: (arguments
          (argument
            value: (integer))))
      (function_call
        function: (function_call
          function: (identifier)
          arguments: (arguments
            (argument
              value: (integer))))
        arguments: (arguments
          (argument
            value: (integer)))))))

================================================================================
Various discard variables
================================================================================

fn ignores(foo, _bar) {
  let _baz = 4
  qux(foo, _hole)
}

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

(source_file
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier))
      (function_parameter
        name: (discard)))
    body: (function_body
      (let
        pattern: (discard)
        value: (integer))
      (function_call
        function: (identifier)
        arguments: (arguments
          (argument
            value: (identifier))
          (argument
            value: (hole)))))))

================================================================================
Weird lists
================================================================================

fn lists(x) {
  []
  [1,]
  [1 ..x]
  [1,..x]
}

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

(source_file
  (function
    name: (identifier)
    parameters: (function_parameters
      (function_parameter
        name: (identifier)))
    body: (function_body
      (list)
      (list
        (integer))
      (list
        (integer)
        spread: (identifier))
      (list
        (integer)
        spread: (identifier)))))

================================================================================
Comment in string
================================================================================

io.println("// hello world!\n")

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

(source_file
  (function_call
    function: (field_access
      record: (identifier)
      field: (label))
    arguments: (arguments
      (argument
        value: (string
	  (quoted_content)
	  (escape_sequence))))))
