===
quote & unquote
===

(quote expr)
(unquote (quote expr))

---

(program
  (quote_form
    call: (symbol)
    item: (symbol))
  (unquote_form
    call: (symbol)
    item: (quote_form
            call: (symbol)
            item: (symbol))))

===
bindings + variable forms
===

(local lol 42)
(var (a b c) 42)
(set [a b c] 42)
(set vim.notify #nil)
(global [a b & cs] 42)
(local {:A a : b &as cs} 42)

---

(program
  (local_form
    call: (symbol)
    (binding_pair
      lhs: (symbol_binding)
      rhs: (number)))
  (var_form
    call: (symbol)
    (binding_pair
      lhs: (list_binding
             item: (symbol_binding)
             item: (symbol_binding)
             item: (symbol_binding))
      rhs: (number)))
  (set_form
    call: (symbol)
    (binding_pair
      lhs: (sequence_binding
             item: (symbol_binding)
             item: (symbol_binding)
             item: (symbol_binding))
      rhs: (number)))
  (set_form
    call: (symbol)
    (binding_pair
      lhs: (multi_symbol
             base: (symbol_fragment)
             member: (symbol_fragment))
      rhs: (hashfn_reader_macro
             expression: (nil))))
  (global_form
    call: (symbol)
    (binding_pair
      lhs: (sequence_binding
            item: (symbol_binding)
            item: (symbol_binding)
            item: (rest_binding
                    lhs: (symbol_option)
                    rhs: (symbol_binding)))
          rhs: (number)))
  (local_form
    call: (symbol)
    (binding_pair
      lhs: (table_binding
             item: (table_binding_pair
                     key: (string_binding
                            content: (string_content))
                     value: (symbol_binding))
             item: (table_binding_pair
                     key: (symbol_binding)
                     value: (symbol_binding))
             item: (table_binding_pair
                     key: (symbol_option)
                     value: (symbol_binding)))
      rhs: (number))))

===
let
===

(let [key value
      (one two three) (values 1 2 3)
      [a & bs] [1 2 3 4]]
  (print :one)
  (print "two"))

---

(program
  (let_form
    call: (symbol)
    vars: (let_vars
            (binding_pair
              lhs: (symbol_binding)
              rhs: (symbol))
            (binding_pair
              lhs: (list_binding
                     item: (symbol_binding)
                     item: (symbol_binding)
                     item: (symbol_binding))
              rhs: (list
                     call: (symbol)
                     item: (number)
                     item: (number)
                     item: (number)))
            (binding_pair
              lhs: (sequence_binding
                     item: (symbol_binding)
                     item: (rest_binding
                             lhs: (symbol_option)
                             rhs: (symbol_binding)))
              rhs: (sequence
                     item: (number)
                     item: (number)
                     item: (number)
                     item: (number))))
    item: (list
            call: (symbol)
            item: (string
                    content: (string_content)))
    item: (list
            call: (symbol)
            item: (string
                    content: (string_content)))))

===
function definition
===

(fn abcs [a b c] {: a : b : c})
(fn abcs-but-with-varargs [a b ...] [...])
(fn nobody [])

(lambda ab.cs [a b & cs]
  (print a)
  (print b)
  (print cs))

---

(program
  (fn_form
    call: (symbol)
    name: (symbol)
    args: (sequence_arguments
            item: (symbol_binding)
            item: (symbol_binding)
            item: (symbol_binding))
    item: (table
            item: (table_pair
                    key: (symbol)
                    value: (symbol))
            item: (table_pair
                    key: (symbol)
                    value: (symbol))
            item: (table_pair
                    key: (symbol)
                    value: (symbol))))
  (fn_form
    call: (symbol)
    name: (symbol)
    args: (sequence_arguments
            item: (symbol_binding)
            item: (symbol_binding)
            item: (symbol_binding))
    item: (sequence
            item: (symbol)))
  (fn_form
    call: (symbol)
    name: (symbol)
    args: (sequence_arguments))
  (lambda_form
    call: (symbol)
    name: (multi_symbol
            base: (symbol_fragment)
            member: (symbol_fragment))
    args: (sequence_arguments
            item: (symbol_binding)
            item: (symbol_binding)
            item: (rest_binding
                    lhs: (symbol_option)
                    rhs: (symbol_binding)))
    item: (list
            call: (symbol)
            item: (symbol))
    item: (list
            call: (symbol)
            item: (symbol))
    item: (list
            call: (symbol)
            item: (symbol))))

===
function metadata
===

(λ ooo-docstring [] :docstring a)
(λ booo-no-docstring [] :not-docstring)
(λ booo-no-docstring [] {:fnl/docstring "not-docstring"})

(fn ayo-some-metadata-over-here [a b & cs]
  "This function does something..."
  {"fnl/arglist" [a b & cs]
   :fnl/docstring "Ha! Now it's a different docstring!"
   "deprecated" "0.9"}
  b)

(lambda just-meta-no-doc [a b c]
  {"dawg" "🐕"}
  c)

---

(program
  (lambda_form
    call: (symbol)
    name: (symbol)
    args: (sequence_arguments)
    docstring: (docstring
                 content: (string_content))
    item: (symbol))
  (lambda_form
    call: (symbol)
    name: (symbol)
    args: (sequence_arguments)
    item: (string
            content: (string_content)))
  (lambda_form
    call: (symbol)
    name: (symbol)
    args: (sequence_arguments)
    item: (table
            item: (table_pair
                    key: (string
                           content: (string_content))
                    value: (string
                             content: (string_content)))))
  (fn_form
    call: (symbol)
    name: (symbol)
    args: (sequence_arguments
            item: (symbol_binding)
            item: (symbol_binding)
            item: (rest_binding
                    lhs: (symbol_option)
                    rhs: (symbol_binding)))
    docstring: (docstring
                 content: (string_content))
    metadata: (table_metadata
                item: (table_metadata_pair
                        key: (string
                               content: (string_content))
                        value: (sequence_arguments
                                 item: (symbol_binding)
                                 item: (symbol_binding)
                                 item: (rest_binding
                                         lhs: (symbol_option)
                                         rhs: (symbol_binding))))
                item: (table_metadata_pair
                        key: (string
                               content: (string_content))
                        value: (docstring
                                 content: (string_content)))
                item: (table_metadata_pair
                        key: (string
                               content: (string_content))
                        value: (string
                                 content: (string_content))))
    item: (symbol))
  (lambda_form
    call: (symbol)
    name: (symbol)
    args: (sequence_arguments
            item: (symbol_binding)
            item: (symbol_binding)
            item: (symbol_binding))
    metadata: (table_metadata
                item: (table_metadata_pair
                        key: (string
                               content: (string_content))
                        value: (string
                                 content: (string_content))))
    item: (symbol)))

===
hashfn
===

(hashfn (+ 1 2))
(hashfn #(+ 1 2))

---

(program
  (hashfn_form
    call: (symbol)
    item: (list
            call: (symbol)
            item: (number)
            item: (number)))
  (hashfn_form
    call: (symbol)
    item: (hashfn_reader_macro
            expression: (list
                    call: (symbol)
                    item: (number)
                    item: (number)))))

===
case & match
===

(case lol
  (= boogy) 253
  (a b c) (values 1 2 3)
  [a b c] [1 2 3]
  [a b & cs] [1 2 3 4 5 6]
  {: lol :mama mia} {:lol 42 :mama 69})
(match lol
  (= boogy) 253
  (a b c) (values 1 2 3)
  [a b c] [1 2 3]
  [a b & cs] [1 2 3 4 5 6]
  {: lol :mama mia} {:lol 42 :mama 69})

---

(program
  (case_form
    call: (symbol)
    item: (symbol)
    (case_pair
      lhs: (list_binding
             item: (symbol_binding)
             item: (symbol_binding))
      rhs: (number))
    (case_pair
      lhs: (list_binding
             item: (symbol_binding)
             item: (symbol_binding)
             item: (symbol_binding))
      rhs: (list
             call: (symbol)
             item: (number)
             item: (number)
             item: (number)))
    (case_pair
      lhs: (sequence_binding
             item: (symbol_binding)
             item: (symbol_binding)
             item: (symbol_binding))
      rhs: (sequence
             item: (number)
             item: (number)
             item: (number)))
    (case_pair
      lhs: (sequence_binding
             item: (symbol_binding)
             item: (symbol_binding)
             item: (rest_binding
                     lhs: (symbol_option)
                     rhs: (symbol_binding)))
      rhs: (sequence
             item: (number)
             item: (number)
             item: (number)
             item: (number)
             item: (number)
             item: (number)))
    (case_pair
      lhs: (table_binding
             item: (table_binding_pair
                     key: (symbol_binding)
                     value: (symbol_binding))
             item: (table_binding_pair
                     key: (string_binding
                            content: (string_content))
                     value: (symbol_binding)))
      rhs: (table
             item: (table_pair
                     key: (string
                            content: (string_content))
                     value: (number))
             item: (table_pair
                     key: (string
                            content: (string_content))
                     value: (number)))))
  (match_form
    call: (symbol)
    item: (symbol)
    (case_pair
      lhs: (list_binding
             item: (symbol_binding)
             item: (symbol_binding))
      rhs: (number))
    (case_pair
      lhs: (list_binding
             item: (symbol_binding)
             item: (symbol_binding)
             item: (symbol_binding))
      rhs: (list
             call: (symbol)
             item: (number)
             item: (number)
             item: (number)))
    (case_pair
      lhs: (sequence_binding
             item: (symbol_binding)
             item: (symbol_binding)
             item: (symbol_binding))
      rhs: (sequence
             item: (number)
             item: (number)
             item: (number)))
    (case_pair
      lhs: (sequence_binding
             item: (symbol_binding)
             item: (symbol_binding)
             item: (rest_binding
                     lhs: (symbol_option)
                     rhs: (symbol_binding)))
      rhs: (sequence
             item: (number)
             item: (number)
             item: (number)
             item: (number)
             item: (number)
             item: (number)))
    (case_pair
      lhs: (table_binding
             item: (table_binding_pair
                     key: (symbol_binding)
                     value: (symbol_binding))
             item: (table_binding_pair
                     key: (string_binding
                            content: (string_content))
                     value: (symbol_binding)))
      rhs: (table
             item: (table_pair
                     key: (string
                            content: (string_content))
                     value: (number))
             item: (table_pair
                     key: (string
                            content: (string_content))
                     value: (number))))))

===
case-try & match-try
===

(case-try (conn:receive :*l)
  input (parse input)
  (command-name params (= token)) (commands.get command-name)
  command (pcall command (table.unpack params))
  (catch
    (_ :timeout) nil
    (_ :closed) (pcall disconnect conn "connection closed")
    (_ msg) (print "Error handling input" msg)))
(match-try (conn:receive :*l)
  input (parse input)
  (command-name params (= token)) (commands.get command-name)
  command (pcall command (table.unpack params))
  (catch
    (_ :timeout) nil
    (_ :closed) (pcall disconnect conn "connection closed")
    (_ msg) (print "Error handling input" msg)))

---

(program
  (case_try_form
    call: (symbol)
    item: (list
            call: (multi_symbol_method
                    base: (symbol_fragment)
                    method: (symbol_fragment))
            item: (string
                    content: (string_content)))
    (case_pair
      lhs: (symbol_binding)
      rhs: (list
             call: (symbol)
             item: (symbol)))
    (case_pair
      lhs: (list_binding
             item: (symbol_binding)
             item: (symbol_binding)
             item: (list_binding
                     item: (symbol_binding)
                     item: (symbol_binding)))
      rhs: (list
             call: (multi_symbol
                     base: (symbol_fragment)
                     member: (symbol_fragment))
             item: (symbol)))
    (case_pair
      lhs: (symbol_binding)
      rhs: (list
             call: (symbol)
             item: (symbol)
             item: (list
                     call: (multi_symbol
                             base: (symbol_fragment)
                             member: (symbol_fragment))
                     item: (symbol))))
    catch: (case_catch
             call: (symbol)
             (case_pair
               lhs: (list_binding
                      item: (symbol_binding)
                      item: (string_binding
                              content: (string_content)))
               rhs: (nil))
             (case_pair
               lhs: (list_binding
                      item: (symbol_binding)
                      item: (string_binding
                              content: (string_content)))
               rhs: (list
                      call: (symbol)
                      item: (symbol)
                      item: (symbol)
                      item: (string
                              content: (string_content))))
             (case_pair
               lhs: (list_binding
                      item: (symbol_binding)
                      item: (symbol_binding))
               rhs: (list
                      call: (symbol)
                      item: (string
                              content: (string_content))
                      item: (symbol)))))
  (match_try_form
    call: (symbol)
    item: (list
            call: (multi_symbol_method
                    base: (symbol_fragment)
                    method: (symbol_fragment))
            item: (string
                    content: (string_content)))
    (case_pair
      lhs: (symbol_binding)
      rhs: (list
             call: (symbol)
             item: (symbol)))
    (case_pair
      lhs: (list_binding
             item: (symbol_binding)
             item: (symbol_binding)
             item: (list_binding
                     item: (symbol_binding)
                     item: (symbol_binding)))
      rhs: (list
             call: (multi_symbol
                     base: (symbol_fragment)
                     member: (symbol_fragment))
             item: (symbol)))
    (case_pair
      lhs: (symbol_binding)
      rhs: (list
             call: (symbol)
             item: (symbol)
             item: (list
                     call: (multi_symbol
                             base: (symbol_fragment)
                             member: (symbol_fragment))
                     item: (symbol))))
    catch: (case_catch
             call: (symbol)
             (case_pair
               lhs: (list_binding
                      item: (symbol_binding)
                      item: (string_binding
                              content: (string_content)))
               rhs: (nil))
             (case_pair
               lhs: (list_binding
                      item: (symbol_binding)
                      item: (string_binding
                              content: (string_content)))
               rhs: (list
                      call: (symbol)
                      item: (symbol)
                      item: (symbol)
                      item: (string
                              content: (string_content))))
             (case_pair
               lhs: (list_binding
                      item: (symbol_binding)
                      item: (symbol_binding))
               rhs: (list
                      call: (symbol)
                      item: (string
                              content: (string_content))
                      item: (symbol))))))

===
case guard
===

(case 42
  (where a (= 69 a)) "nice!"
  (where [a b] (= 42 a) (not= :poo b)) "The answer"
  (where (or (a b) [a b])))

---

(program
  (case_form
    call: (symbol)
    item: (number)
    (case_pair
      lhs: (case_guard
             call: (symbol)
             item: (symbol_binding)
             guard: (list
                      call: (symbol)
                      item: (number)
                      item: (symbol)))
      rhs: (string
             content: (string_content)))
    (case_pair
      lhs: (case_guard
             call: (symbol)
             item: (sequence_binding
                     item: (symbol_binding)
                     item: (symbol_binding))
             guard: (list
                      call: (symbol)
                      item: (number)
                      item: (symbol))
             guard: (list
                      call: (symbol)
                      item: (string
                              content: (string_content))
                      item: (symbol)))
      rhs: (string
             content: (string_content)))
    (case_pair
      lhs: (case_guard
             call: (symbol)
             item: (case_guard_or_special
                     call: (symbol)
                     item: (list_binding
                             item: (symbol_binding)
                             item: (symbol_binding))
                     item: (sequence_binding
                             item: (symbol_binding)
                             item: (symbol_binding)))))))

===
each
===

(each [key value (pairs mytbl)
       &until (rand)]
  (print "executing key")
  (print (f value)))

(each [42 nil nil :until true])

---

(program
  (each_form
    call: (symbol)
    iter_body: (iter_body
                 binding: (symbol_binding)
                 binding: (symbol_binding)
                 iterator: (list
                             call: (symbol)
                             item: (symbol))
                 option: (iter_option
                           option: (symbol_option)
                           value: (list
                                    call: (symbol))))
    item: (list
            call: (symbol)
            item: (string
                    content: (string_content)))
    item: (list
            call: (symbol)
            item: (list
                    call: (symbol)
                    item: (symbol))))
  (each_form
    call: (symbol)
    iter_body: (iter_body
                 binding: (number_binding)
                 binding: (nil_binding)
                 iterator: (nil)
                 option: (iter_option
                           option: (symbol_option)
                           value: (boolean)))))

===
if
===

(if cond
  then
  else)

---

(program
  (if_form
    call: (symbol)
    (if_pair
      condition: (symbol)
      expression: (symbol))
    else: (symbol)))

===
import-macros
===

(import-macros {: some : thting} :globgobgabgalab)

---

(program
  (import_macros_form
    call: (symbol)
    imports: (table_binding
               item: (table_binding_pair
                       key: (symbol_binding)
                       value: (symbol_binding))
               item: (table_binding_pair
                       key: (symbol_binding)
                       value: (symbol_binding)))
    module: (string
              content: (string_content))))

===
macro
===

(macro abc [lol]
  ting)

---

(program
  (macro_form
    call: (symbol)
    name: (symbol)
    args: (sequence_arguments
            item: (symbol_binding))
    item: (symbol)))
