(module main)

(enum Status Ready Blocked)

(struct Pair
  (left i32)
  (right i32))

(struct CompositeRecord
  (ints (vec i32))
  (wides (vec i64))
  (ratios (vec f64))
  (flags (vec bool))
  (labels (vec string))
  (maybe_count (option i32))
  (maybe_wide (option i64))
  (maybe_ratio (option f64))
  (maybe_flag (option bool))
  (maybe_label (option string))
  (count_result (result i32 i32))
  (wide_result (result i64 i32))
  (ratio_result (result f64 i32))
  (flag_result (result bool i32))
  (label_result (result string i32))
  (pair Pair)
  (status Status))

(fn make_pair ((left i32) (right i32)) -> Pair
  (Pair (left left) (right right)))

(fn vec_i32_pair ((base i32)) -> (vec i32)
  (let values (vec i32) (std.vec.i32.empty))
  (let first (vec i32) (std.vec.i32.append values base))
  (std.vec.i32.append first (+ base 1)))

(fn vec_i64_pair ((base i64)) -> (vec i64)
  (let values (vec i64) (std.vec.i64.empty))
  (let first (vec i64) (std.vec.i64.append values base))
  (std.vec.i64.append first (+ base 1i64)))

(fn vec_f64_pair ((base f64)) -> (vec f64)
  (let values (vec f64) (std.vec.f64.empty))
  (let first (vec f64) (std.vec.f64.append values base))
  (std.vec.f64.append first (+ base 1.0)))

(fn vec_bool_pair ((first bool) (second bool)) -> (vec bool)
  (let values (vec bool) (std.vec.bool.empty))
  (let left (vec bool) (std.vec.bool.append values first))
  (std.vec.bool.append left second))

(fn vec_string_pair ((first string) (second string)) -> (vec string)
  (let values (vec string) (std.vec.string.empty))
  (let left (vec string) (std.vec.string.append values first))
  (std.vec.string.append left second))

(fn make_record () -> CompositeRecord
  (CompositeRecord (ints (vec_i32_pair 10)) (wides (vec_i64_pair 100i64)) (ratios (vec_f64_pair 3.5)) (flags (vec_bool_pair false true)) (labels (vec_string_pair "oak" "elm")) (maybe_count (some i32 7)) (maybe_wide (some i64 7000000000i64)) (maybe_ratio (some f64 7.5)) (maybe_flag (some bool true)) (maybe_label (some string "alpha")) (count_result (ok i32 i32 9)) (wide_result (ok i64 i32 9000000000i64)) (ratio_result (ok f64 i32 9.25)) (flag_result (ok bool i32 true)) (label_result (ok string i32 "beta")) (pair (make_pair 20 22)) (status (Status.Ready))))

(fn echo_record ((record CompositeRecord)) -> CompositeRecord
  record)

(fn local_record () -> CompositeRecord
  (let record CompositeRecord (make_record))
  (echo_record record))

(fn ints_second ((record CompositeRecord)) -> i32
  (std.vec.i32.index (. record ints) 1))

(fn wides_second ((record CompositeRecord)) -> i64
  (std.vec.i64.index (. record wides) 1))

(fn ratios_second ((record CompositeRecord)) -> f64
  (std.vec.f64.index (. record ratios) 1))

(fn flags_second ((record CompositeRecord)) -> bool
  (std.vec.bool.index (. record flags) 1))

(fn labels_second ((record CompositeRecord)) -> string
  (std.vec.string.index (. record labels) 1))

(fn maybe_count_value ((record CompositeRecord)) -> i32
  (match (. record maybe_count)
    ((some payload)
      payload)
    ((none)
      0)))

(fn maybe_wide_value ((record CompositeRecord)) -> i64
  (match (. record maybe_wide)
    ((some payload)
      payload)
    ((none)
      0i64)))

(fn maybe_ratio_value ((record CompositeRecord)) -> f64
  (match (. record maybe_ratio)
    ((some payload)
      payload)
    ((none)
      0.0)))

(fn maybe_flag_value ((record CompositeRecord)) -> bool
  (match (. record maybe_flag)
    ((some payload)
      payload)
    ((none)
      false)))

(fn maybe_label_value ((record CompositeRecord)) -> string
  (match (. record maybe_label)
    ((some payload)
      payload)
    ((none)
      "missing")))

(fn count_result_value ((record CompositeRecord)) -> i32
  (match (. record count_result)
    ((ok payload)
      payload)
    ((err code)
      code)))

(fn wide_result_value ((record CompositeRecord)) -> i64
  (match (. record wide_result)
    ((ok payload)
      payload)
    ((err code)
      0i64)))

(fn ratio_result_value ((record CompositeRecord)) -> f64
  (match (. record ratio_result)
    ((ok payload)
      payload)
    ((err code)
      0.0)))

(fn flag_result_value ((record CompositeRecord)) -> bool
  (match (. record flag_result)
    ((ok payload)
      payload)
    ((err code)
      false)))

(fn label_result_value ((record CompositeRecord)) -> string
  (match (. record label_result)
    ((ok payload)
      payload)
    ((err code)
      "missing")))

(fn pair_total ((record CompositeRecord)) -> i32
  (+ (. (. record pair) left) (. (. record pair) right)))

(fn is_ready ((record CompositeRecord)) -> bool
  (= (. record status) (Status.Ready)))

(test "struct vec i32 field access"
  (= (ints_second (make_record)) 11))

(test "struct vec i64 field access"
  (= (wides_second (make_record)) 101i64))

(test "struct vec f64 field access"
  (= (ratios_second (make_record)) 4.5))

(test "struct vec bool field access"
  (flags_second (make_record)))

(test "struct vec string field access"
  (= (labels_second (make_record)) "elm"))

(test "struct option i32 field access"
  (= (maybe_count_value (make_record)) 7))

(test "struct option i64 field access"
  (= (maybe_wide_value (make_record)) 7000000000i64))

(test "struct option f64 field access"
  (= (maybe_ratio_value (make_record)) 7.5))

(test "struct option bool field access"
  (maybe_flag_value (make_record)))

(test "struct option string field access"
  (= (maybe_label_value (make_record)) "alpha"))

(test "struct result i32 field access"
  (= (count_result_value (make_record)) 9))

(test "struct result i64 field access"
  (= (wide_result_value (make_record)) 9000000000i64))

(test "struct result f64 field access"
  (= (ratio_result_value (make_record)) 9.25))

(test "struct result bool field access"
  (flag_result_value (make_record)))

(test "struct result string field access"
  (= (label_result_value (make_record)) "beta"))

(test "nested struct field access"
  (= (pair_total (make_record)) 42))

(test "nested struct local param return call flow"
  (= (pair_total (local_record)) 42))

(test "direct enum struct field equality"
  (is_ready (make_record)))

(fn main () -> i32
  (pair_total (local_record)))
