================================================================================
config-gcc.ncl
================================================================================

# Validate and normalize gcc flags. They can be either a string `-Wextra` or
# a structured value `{flag = "W", arg = "extra"}`. Arguments are not checked.
let GccFlag =
  # We only allow the following flags
  let available = ["W", "c", "S", "e", "o"] in
  fun label value =>
  if builtin.is_str value then
    if string.length value > 0 &&
      array.any (fun x => x == string.substring 0 1 value) available then
      value
    else
      contract.blame_with "unknown flag %{value}" label
  else if builtin.is_record value then
    if record.has_field "flag" value && record.has_field "arg" value then
      if array.any (fun x => x == value.flag) available then
        #Normalize the tag to a string
        value.flag ++ value.arg
      else
        contract.blame_with "unknown flag %{value.flag}" label
    else
      contract.blame_with
        "bad record structure: missing field `flag` or `arg`"
        label
  else
    contract.blame_with "expected record or string" label in

let Path =
  let pattern = m%"^(.+)/([^/]+)$"% in
  fun label value =>
    if builtin.is_str value then
      if string.is_match pattern value then
        value
      else
        contract.blame_with "invalid path" label
    else
      contract.blame_with "not a string" label in

let SharedObjectFile = fun label value =>
  if builtin.is_str value then
    if string.is_match m%"\.so$"% value then
      value
    else
      contract.blame_with "not an .so file" label
  else
    contract.blame_with "not a string" label in

let OptLevel = fun label value =>
  if value == 0 || value == 1 || value == 2 then
    value
  else
    contract.blame label in

let Contract = {
  path_libc | doc "Path to libc."
            | Path
            | SharedObjectFile
            | default = "/lib/x86_64-linux-gnu/libc.so",

  flags | doc "
            Additional flags to pass to GCC. Either provide a string without the
            leading `-`, or a structured value `{flag : Str, arg: Str}`.
          "
        | Array GccFlag
        | default = [],

  optimization_level | doc "
                       Optimization level. Possible values:

                        - *0*: unoptimized
                        - *1*: normal
                        - *2*: use optimizations
                      "
                     | OptLevel
                     | default = 1,
} in

{
  flags = ["Wextra", {flag = "o", arg = "stuff.o"}],
  optimization_level = 2,
} | Contract

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

(term
  (comment)
  (comment)
  (uni_term
    (let_expr
      (let_in_block
        (let_binding
          (pattern
            (ident))
          (comment)
          (term
            (uni_term
              (let_expr
                (let_in_block
                  (let_binding
                    (pattern
                      (ident))
                    (term
                      (uni_term
                        (infix_expr
                          (applicative
                            (record_operand
                              (atom
                                (term
                                  (uni_term
                                    (infix_expr
                                      (applicative
                                        (record_operand
                                          (atom
                                            (str_chunks
                                              (str_chunks_single
                                                (chunk_literal_single
                                                  (str_literal))))))))))
                                (term
                                  (uni_term
                                    (infix_expr
                                      (applicative
                                        (record_operand
                                          (atom
                                            (str_chunks
                                              (str_chunks_single
                                                (chunk_literal_single
                                                  (str_literal))))))))))
                                (term
                                  (uni_term
                                    (infix_expr
                                      (applicative
                                        (record_operand
                                          (atom
                                            (str_chunks
                                              (str_chunks_single
                                                (chunk_literal_single
                                                  (str_literal))))))))))
                                (term
                                  (uni_term
                                    (infix_expr
                                      (applicative
                                        (record_operand
                                          (atom
                                            (str_chunks
                                              (str_chunks_single
                                                (chunk_literal_single
                                                  (str_literal))))))))))
                                (term
                                  (uni_term
                                    (infix_expr
                                      (applicative
                                        (record_operand
                                          (atom
                                            (str_chunks
                                              (str_chunks_single
                                                (chunk_literal_single
                                                  (str_literal))))))))))))))))))
                (term
                  (uni_term
                    (fun_expr
                      (pattern_fun
                        (ident))
                      (pattern_fun
                        (ident))
                      (term
                        (uni_term
                          (ite_expr
                            (term
                              (uni_term
                                (infix_expr
                                  (applicative
                                    (applicative
                                      (record_operand
                                        (record_operation_chain
                                          (record_operand
                                            (atom
                                              (ident)))
                                          (ident))))
                                    (record_operand
                                      (atom
                                        (ident)))))))
                            (term
                              (uni_term
                                (ite_expr
                                  (term
                                    (uni_term
                                      (infix_expr
                                        (infix_expr
                                          (infix_expr
                                            (applicative
                                              (applicative
                                                (record_operand
                                                  (record_operation_chain
                                                    (record_operand
                                                      (atom
                                                        (ident)))
                                                    (ident))))
                                              (record_operand
                                                (atom
                                                  (ident)))))
                                          (infix_b_op_7)
                                          (infix_expr
                                            (applicative
                                              (record_operand
                                                (atom
                                                  (num_literal))))))
                                        (infix_lazy_b_op_9)
                                        (infix_expr
                                          (applicative
                                            (applicative
                                              (applicative
                                                (record_operand
                                                  (record_operation_chain
                                                    (record_operand
                                                      (atom
                                                        (ident)))
                                                    (ident))))
                                              (record_operand
                                                (atom
                                                  (uni_term
                                                    (fun_expr
                                                      (pattern_fun
                                                        (ident))
                                                      (term
                                                        (uni_term
                                                          (infix_expr
                                                            (infix_expr
                                                              (applicative
                                                                (record_operand
                                                                  (atom
                                                                    (ident)))))
                                                            (infix_b_op_8)
                                                            (infix_expr
                                                              (applicative
                                                                (applicative
                                                                  (applicative
                                                                    (applicative
                                                                      (record_operand
                                                                        (record_operation_chain
                                                                          (record_operand
                                                                            (atom
                                                                              (ident)))
                                                                          (ident))))
                                                                    (record_operand
                                                                      (atom
                                                                        (num_literal))))
                                                                  (record_operand
                                                                    (atom
                                                                      (num_literal))))
                                                                (record_operand
                                                                  (atom
                                                                    (ident)))))))))))))
                                            (record_operand
                                              (atom
                                                (ident))))))))
                                  (term
                                    (uni_term
                                      (infix_expr
                                        (applicative
                                          (record_operand
                                            (atom
                                              (ident)))))))
                                  (term
                                    (uni_term
                                      (infix_expr
                                        (applicative
                                          (applicative
                                            (applicative
                                              (record_operand
                                                (record_operation_chain
                                                  (record_operand
                                                    (atom
                                                      (ident)))
                                                  (ident))))
                                            (record_operand
                                              (atom
                                                (str_chunks
                                                  (str_chunks_single
                                                    (chunk_literal_single
                                                      (str_literal))
                                                    (chunk_expr
                                                      (interpolation_start)
                                                      (term
                                                        (uni_term
                                                          (infix_expr
                                                            (applicative
                                                              (record_operand
                                                                (atom
                                                                  (ident)))))))
                                                      (interpolation_end)))))))
                                          (record_operand
                                            (atom
                                              (ident))))))))))
                            (term
                              (uni_term
                                (ite_expr
                                  (term
                                    (uni_term
                                      (infix_expr
                                        (applicative
                                          (applicative
                                            (record_operand
                                              (record_operation_chain
                                                (record_operand
                                                  (atom
                                                    (ident)))
                                                (ident))))
                                          (record_operand
                                            (atom
                                              (ident)))))))
                                  (term
                                    (uni_term
                                      (ite_expr
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (infix_expr
                                                (applicative
                                                  (applicative
                                                    (applicative
                                                      (record_operand
                                                        (record_operation_chain
                                                          (record_operand
                                                            (atom
                                                              (ident)))
                                                          (ident))))
                                                    (record_operand
                                                      (atom
                                                        (str_chunks
                                                          (str_chunks_single
                                                            (chunk_literal_single
                                                              (str_literal)))))))
                                                  (record_operand
                                                    (atom
                                                      (ident)))))
                                              (infix_lazy_b_op_9)
                                              (infix_expr
                                                (applicative
                                                  (applicative
                                                    (applicative
                                                      (record_operand
                                                        (record_operation_chain
                                                          (record_operand
                                                            (atom
                                                              (ident)))
                                                          (ident))))
                                                    (record_operand
                                                      (atom
                                                        (str_chunks
                                                          (str_chunks_single
                                                            (chunk_literal_single
                                                              (str_literal)))))))
                                                  (record_operand
                                                    (atom
                                                      (ident))))))))
                                        (term
                                          (uni_term
                                            (ite_expr
                                              (term
                                                (uni_term
                                                  (infix_expr
                                                    (applicative
                                                      (applicative
                                                        (applicative
                                                          (record_operand
                                                            (record_operation_chain
                                                              (record_operand
                                                                (atom
                                                                  (ident)))
                                                              (ident))))
                                                        (record_operand
                                                          (atom
                                                            (uni_term
                                                              (fun_expr
                                                                (pattern_fun
                                                                  (ident))
                                                                (term
                                                                  (uni_term
                                                                    (infix_expr
                                                                      (infix_expr
                                                                        (applicative
                                                                          (record_operand
                                                                            (atom
                                                                              (ident)))))
                                                                      (infix_b_op_8)
                                                                      (infix_expr
                                                                        (applicative
                                                                          (record_operand
                                                                            (record_operation_chain
                                                                              (record_operand
                                                                                (atom
                                                                                  (ident)))
                                                                              (ident)))))))))))))
                                                      (record_operand
                                                        (atom
                                                          (ident)))))))
                                              (comment)
                                              (term
                                                (uni_term
                                                  (infix_expr
                                                    (infix_expr
                                                      (applicative
                                                        (record_operand
                                                          (record_operation_chain
                                                            (record_operand
                                                              (atom
                                                                (ident)))
                                                            (ident)))))
                                                    (infix_b_op_2)
                                                    (infix_expr
                                                      (applicative
                                                        (record_operand
                                                          (record_operation_chain
                                                            (record_operand
                                                              (atom
                                                                (ident)))
                                                            (ident))))))))
                                              (term
                                                (uni_term
                                                  (infix_expr
                                                    (applicative
                                                      (applicative
                                                        (applicative
                                                          (record_operand
                                                            (record_operation_chain
                                                              (record_operand
                                                                (atom
                                                                  (ident)))
                                                              (ident))))
                                                        (record_operand
                                                          (atom
                                                            (str_chunks
                                                              (str_chunks_single
                                                                (chunk_literal_single
                                                                  (str_literal))
                                                                (chunk_expr
                                                                  (interpolation_start)
                                                                  (term
                                                                    (uni_term
                                                                      (infix_expr
                                                                        (applicative
                                                                          (record_operand
                                                                            (record_operation_chain
                                                                              (record_operand
                                                                                (atom
                                                                                  (ident)))
                                                                              (ident)))))))
                                                                  (interpolation_end)))))))
                                                      (record_operand
                                                        (atom
                                                          (ident))))))))))
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (applicative
                                                (applicative
                                                  (applicative
                                                    (record_operand
                                                      (record_operation_chain
                                                        (record_operand
                                                          (atom
                                                            (ident)))
                                                        (ident))))
                                                  (record_operand
                                                    (atom
                                                      (str_chunks
                                                        (str_chunks_single
                                                          (chunk_literal_single
                                                            (str_literal)))))))
                                                (record_operand
                                                  (atom
                                                    (ident))))))))))
                                  (term
                                    (uni_term
                                      (infix_expr
                                        (applicative
                                          (applicative
                                            (applicative
                                              (record_operand
                                                (record_operation_chain
                                                  (record_operand
                                                    (atom
                                                      (ident)))
                                                  (ident))))
                                            (record_operand
                                              (atom
                                                (str_chunks
                                                  (str_chunks_single
                                                    (chunk_literal_single
                                                      (str_literal)))))))
                                          (record_operand
                                            (atom
                                              (ident)))))))))))))))))))))
      (term
        (uni_term
          (let_expr
            (let_in_block
              (let_binding
                (pattern
                  (ident))
                (term
                  (uni_term
                    (let_expr
                      (let_in_block
                        (let_binding
                          (pattern
                            (ident))
                          (term
                            (uni_term
                              (infix_expr
                                (applicative
                                  (record_operand
                                    (atom
                                      (str_chunks
                                        (str_chunks_multi
                                          (multstr_start)
                                          (chunk_literal_multi
                                            (mult_str_literal))
                                          (multstr_end)))))))))))
                      (term
                        (uni_term
                          (fun_expr
                            (pattern_fun
                              (ident))
                            (pattern_fun
                              (ident))
                            (term
                              (uni_term
                                (ite_expr
                                  (term
                                    (uni_term
                                      (infix_expr
                                        (applicative
                                          (applicative
                                            (record_operand
                                              (record_operation_chain
                                                (record_operand
                                                  (atom
                                                    (ident)))
                                                (ident))))
                                          (record_operand
                                            (atom
                                              (ident)))))))
                                  (term
                                    (uni_term
                                      (ite_expr
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (applicative
                                                (applicative
                                                  (applicative
                                                    (record_operand
                                                      (record_operation_chain
                                                        (record_operand
                                                          (atom
                                                            (ident)))
                                                        (ident))))
                                                  (record_operand
                                                    (atom
                                                      (ident))))
                                                (record_operand
                                                  (atom
                                                    (ident)))))))
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (applicative
                                                (record_operand
                                                  (atom
                                                    (ident)))))))
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (applicative
                                                (applicative
                                                  (applicative
                                                    (record_operand
                                                      (record_operation_chain
                                                        (record_operand
                                                          (atom
                                                            (ident)))
                                                        (ident))))
                                                  (record_operand
                                                    (atom
                                                      (str_chunks
                                                        (str_chunks_single
                                                          (chunk_literal_single
                                                            (str_literal)))))))
                                                (record_operand
                                                  (atom
                                                    (ident))))))))))
                                  (term
                                    (uni_term
                                      (infix_expr
                                        (applicative
                                          (applicative
                                            (applicative
                                              (record_operand
                                                (record_operation_chain
                                                  (record_operand
                                                    (atom
                                                      (ident)))
                                                  (ident))))
                                            (record_operand
                                              (atom
                                                (str_chunks
                                                  (str_chunks_single
                                                    (chunk_literal_single
                                                      (str_literal)))))))
                                          (record_operand
                                            (atom
                                              (ident))))))))))))))))))
            (term
              (uni_term
                (let_expr
                  (let_in_block
                    (let_binding
                      (pattern
                        (ident))
                      (term
                        (uni_term
                          (fun_expr
                            (pattern_fun
                              (ident))
                            (pattern_fun
                              (ident))
                            (term
                              (uni_term
                                (ite_expr
                                  (term
                                    (uni_term
                                      (infix_expr
                                        (applicative
                                          (applicative
                                            (record_operand
                                              (record_operation_chain
                                                (record_operand
                                                  (atom
                                                    (ident)))
                                                (ident))))
                                          (record_operand
                                            (atom
                                              (ident)))))))
                                  (term
                                    (uni_term
                                      (ite_expr
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (applicative
                                                (applicative
                                                  (applicative
                                                    (record_operand
                                                      (record_operation_chain
                                                        (record_operand
                                                          (atom
                                                            (ident)))
                                                        (ident))))
                                                  (record_operand
                                                    (atom
                                                      (str_chunks
                                                        (str_chunks_multi
                                                          (multstr_start)
                                                          (chunk_literal_multi
                                                            (mult_str_literal))
                                                          (multstr_end))))))
                                                (record_operand
                                                  (atom
                                                    (ident)))))))
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (applicative
                                                (record_operand
                                                  (atom
                                                    (ident)))))))
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (applicative
                                                (applicative
                                                  (applicative
                                                    (record_operand
                                                      (record_operation_chain
                                                        (record_operand
                                                          (atom
                                                            (ident)))
                                                        (ident))))
                                                  (record_operand
                                                    (atom
                                                      (str_chunks
                                                        (str_chunks_single
                                                          (chunk_literal_single
                                                            (str_literal)))))))
                                                (record_operand
                                                  (atom
                                                    (ident))))))))))
                                  (term
                                    (uni_term
                                      (infix_expr
                                        (applicative
                                          (applicative
                                            (applicative
                                              (record_operand
                                                (record_operation_chain
                                                  (record_operand
                                                    (atom
                                                      (ident)))
                                                  (ident))))
                                            (record_operand
                                              (atom
                                                (str_chunks
                                                  (str_chunks_single
                                                    (chunk_literal_single
                                                      (str_literal)))))))
                                          (record_operand
                                            (atom
                                              (ident)))))))))))))))
                  (term
                    (uni_term
                      (let_expr
                        (let_in_block
                          (let_binding
                            (pattern
                              (ident))
                            (term
                              (uni_term
                                (fun_expr
                                  (pattern_fun
                                    (ident))
                                  (pattern_fun
                                    (ident))
                                  (term
                                    (uni_term
                                      (ite_expr
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (infix_expr
                                                (infix_expr
                                                  (infix_expr
                                                    (applicative
                                                      (record_operand
                                                        (atom
                                                          (ident)))))
                                                  (infix_b_op_8)
                                                  (infix_expr
                                                    (applicative
                                                      (record_operand
                                                        (atom
                                                          (num_literal))))))
                                                (infix_lazy_b_op_10)
                                                (infix_expr
                                                  (infix_expr
                                                    (applicative
                                                      (record_operand
                                                        (atom
                                                          (ident)))))
                                                  (infix_b_op_8)
                                                  (infix_expr
                                                    (applicative
                                                      (record_operand
                                                        (atom
                                                          (num_literal)))))))
                                              (infix_lazy_b_op_10)
                                              (infix_expr
                                                (infix_expr
                                                  (applicative
                                                    (record_operand
                                                      (atom
                                                        (ident)))))
                                                (infix_b_op_8)
                                                (infix_expr
                                                  (applicative
                                                    (record_operand
                                                      (atom
                                                        (num_literal)))))))))
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (applicative
                                                (record_operand
                                                  (atom
                                                    (ident)))))))
                                        (term
                                          (uni_term
                                            (infix_expr
                                              (applicative
                                                (applicative
                                                  (record_operand
                                                    (record_operation_chain
                                                      (record_operand
                                                        (atom
                                                          (ident)))
                                                      (ident))))
                                                (record_operand
                                                  (atom
                                                    (ident)))))))))))))))
                        (term
                          (uni_term
                            (let_expr
                              (let_in_block
                                (let_binding
                                  (pattern
                                    (ident))
                                  (term
                                    (uni_term
                                      (infix_expr
                                        (applicative
                                          (record_operand
                                            (atom
                                              (uni_record
                                                (record_field
                                                  (field_path
                                                    (field_path_elem
                                                      (ident)))
                                                  (annot
                                                    (annot_atom
                                                      (static_string
                                                        (chunk_literal_single
                                                          (str_literal))))
                                                    (annot_atom
                                                      (types
                                                        (infix_expr
                                                          (applicative
                                                            (record_operand
                                                              (atom
                                                                (ident)))))))
                                                    (annot_atom
                                                      (types
                                                        (infix_expr
                                                          (applicative
                                                            (record_operand
                                                              (atom
                                                                (ident)))))))
                                                    (annot_atom))
                                                  (term
                                                    (uni_term
                                                      (infix_expr
                                                        (applicative
                                                          (record_operand
                                                            (atom
                                                              (str_chunks
                                                                (str_chunks_single
                                                                  (chunk_literal_single
                                                                    (str_literal)))))))))))
                                                (record_field
                                                  (field_path
                                                    (field_path_elem
                                                      (ident)))
                                                  (annot
                                                    (annot_atom
                                                      (static_string
                                                        (chunk_literal_single
                                                          (str_literal))))
                                                    (annot_atom
                                                      (types
                                                        (infix_expr
                                                          (applicative
                                                            (type_array
                                                              (record_operand
                                                                (atom
                                                                  (ident))))))))
                                                    (annot_atom))
                                                  (term
                                                    (uni_term
                                                      (infix_expr
                                                        (applicative
                                                          (record_operand
                                                            (atom)))))))
                                                (record_field
                                                  (field_path
                                                    (field_path_elem
                                                      (ident)))
                                                  (annot
                                                    (annot_atom
                                                      (static_string
                                                        (chunk_literal_single
                                                          (str_literal))))
                                                    (annot_atom
                                                      (types
                                                        (infix_expr
                                                          (applicative
                                                            (record_operand
                                                              (atom
                                                                (ident)))))))
                                                    (annot_atom))
                                                  (term
                                                    (uni_term
                                                      (infix_expr
                                                        (applicative
                                                          (record_operand
                                                            (atom
                                                              (num_literal)))))))))))))))))
                              (term
                                (uni_term
                                  (annotated_infix_expr
                                    (infix_expr
                                      (applicative
                                        (record_operand
                                          (atom
                                            (uni_record
                                              (record_field
                                                (field_path
                                                  (field_path_elem
                                                    (ident)))
                                                (term
                                                  (uni_term
                                                    (infix_expr
                                                      (applicative
                                                        (record_operand
                                                          (atom
                                                            (term
                                                              (uni_term
                                                                (infix_expr
                                                                  (applicative
                                                                    (record_operand
                                                                      (atom
                                                                        (str_chunks
                                                                          (str_chunks_single
                                                                            (chunk_literal_single
                                                                              (str_literal))))))))))
                                                            (term
                                                              (uni_term
                                                                (infix_expr
                                                                  (applicative
                                                                    (record_operand
                                                                      (atom
                                                                        (uni_record
                                                                          (record_field
                                                                            (field_path
                                                                              (field_path_elem
                                                                                (ident)))
                                                                            (term
                                                                              (uni_term
                                                                                (infix_expr
                                                                                  (applicative
                                                                                    (record_operand
                                                                                      (atom
                                                                                        (str_chunks
                                                                                          (str_chunks_single
                                                                                            (chunk_literal_single
                                                                                              (str_literal)))))))))))
                                                                          (record_last_field
                                                                            (record_field
                                                                              (field_path
                                                                                (field_path_elem
                                                                                  (ident)))
                                                                              (term
                                                                                (uni_term
                                                                                  (infix_expr
                                                                                    (applicative
                                                                                      (record_operand
                                                                                        (atom
                                                                                          (str_chunks
                                                                                            (str_chunks_single
                                                                                              (chunk_literal_single
                                                                                                (str_literal))))))))))))))))))))))))))
                                              (record_field
                                                (field_path
                                                  (field_path_elem
                                                    (ident)))
                                                (term
                                                  (uni_term
                                                    (infix_expr
                                                      (applicative
                                                        (record_operand
                                                          (atom
                                                            (num_literal)))))))))))))
                                    (annot
                                      (annot_atom
                                        (types
                                          (infix_expr
                                            (applicative
                                              (record_operand
                                                (atom
                                                  (ident))))))))))))))))))))))))))
