(module main)

(struct Point
  (x i32)
  (y i32))

(struct PrimitiveRecord
  (id i32)
  (active bool)
  (label string))

(struct NumericRecord
  (wide i64)
  (ratio f64))

(enum Signal Red Yellow Green)

(enum Reading
  Missing
  (Value i32))

(struct TaggedReading
  (status Signal)
  (reading Reading))

(fn make_point ((x i32) (y i32)) -> Point
  (Point (x x) (y y)))

(fn make_primitive_record ((id i32) (label string)) -> PrimitiveRecord
  (PrimitiveRecord (id id) (active (= id 7)) (label label)))

(fn make_numeric_record ((wide i64) (ratio f64)) -> NumericRecord
  (NumericRecord (wide wide) (ratio ratio)))

(fn make_tagged ((status Signal) (reading Reading)) -> TaggedReading
  (TaggedReading (status status) (reading reading)))

(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 swap_string ((first string) (second string)) -> string
  (var current string first)
  (set current second)
  current)

(fn vec_i32_local_value () -> i32
  (var current (vec i32) (vec_i32_pair 10))
  (set current (vec_i32_pair 40))
  (std.vec.i32.index current 1))

(fn vec_i64_local_value () -> i64
  (var current (vec i64) (vec_i64_pair 10i64))
  (set current (vec_i64_pair 40i64))
  (std.vec.i64.index current 1))

(fn vec_f64_local_value () -> f64
  (var current (vec f64) (vec_f64_pair 10.0))
  (set current (vec_f64_pair 40.0))
  (std.vec.f64.index current 1))

(fn vec_bool_local_value () -> bool
  (var current (vec bool) (vec_bool_pair true false))
  (set current (vec_bool_pair false true))
  (std.vec.bool.index current 1))

(fn vec_string_local_value () -> string
  (var current (vec string) (vec_string_pair "oak" "elm"))
  (set current (vec_string_pair "pine" "slovo"))
  (std.vec.string.index current 1))

(fn option_i32_local_value () -> i32
  (var current (option i32) (none i32))
  (set current (some i32 42))
  (match current
    ((some payload)
      payload)
    ((none)
      0)))

(fn option_i64_local_value () -> i64
  (var current (option i64) (none i64))
  (set current (some i64 42000000000i64))
  (match current
    ((some payload)
      payload)
    ((none)
      0i64)))

(fn option_f64_local_value () -> f64
  (var current (option f64) (none f64))
  (set current (some f64 42.5))
  (match current
    ((some payload)
      payload)
    ((none)
      0.0)))

(fn option_bool_local_value () -> bool
  (var current (option bool) (none bool))
  (set current (some bool true))
  (match current
    ((some payload)
      payload)
    ((none)
      false)))

(fn option_string_local_value () -> string
  (var current (option string) (none string))
  (set current (some string "branch"))
  (match current
    ((some payload)
      payload)
    ((none)
      "fallback")))

(fn result_i32_local_value () -> i32
  (var current (result i32 i32) (err i32 i32 7))
  (set current (ok i32 i32 42))
  (match current
    ((ok payload)
      payload)
    ((err code)
      code)))

(fn result_i64_local_value () -> i64
  (var current (result i64 i32) (err i64 i32 7))
  (set current (ok i64 i32 42000000000i64))
  (match current
    ((ok payload)
      payload)
    ((err code)
      0i64)))

(fn result_f64_local_value () -> f64
  (var current (result f64 i32) (err f64 i32 7))
  (set current (ok f64 i32 42.5))
  (match current
    ((ok payload)
      payload)
    ((err code)
      0.0)))

(fn result_bool_local_value () -> bool
  (var current (result bool i32) (err bool i32 7))
  (set current (ok bool i32 true))
  (match current
    ((ok payload)
      payload)
    ((err code)
      false)))

(fn result_string_local_value () -> string
  (var current (result string i32) (err string i32 7))
  (set current (ok string i32 "slovo"))
  (match current
    ((ok payload)
      payload)
    ((err code)
      "fallback")))

(fn point_local_sum () -> i32
  (var current Point (make_point 1 2))
  (set current (make_point 20 22))
  (+ (. current x) (. current y)))

(fn primitive_record_local_label () -> string
  (var current PrimitiveRecord (make_primitive_record 3 "alpha"))
  (set current (make_primitive_record 7 "beta"))
  (. current label))

(fn numeric_record_local_ratio () -> f64
  (var current NumericRecord (make_numeric_record 10i64 1.0))
  (set current (make_numeric_record 20i64 3.5))
  (. current ratio))

(fn signal_local_code () -> i32
  (var current Signal (Signal.Red))
  (set current (Signal.Green))
  (match current
    ((Signal.Red)
      1)
    ((Signal.Yellow)
      2)
    ((Signal.Green)
      3)))

(fn reading_local_code () -> i32
  (var current Reading (Reading.Missing))
  (set current (Reading.Value 42))
  (match current
    ((Reading.Missing)
      0)
    ((Reading.Value payload)
      payload)))

(fn tagged_local_code () -> i32
  (var current TaggedReading (make_tagged (Signal.Yellow) (Reading.Missing)))
  (set current (make_tagged (Signal.Green) (Reading.Value 42)))
  (match (. current reading)
    ((Reading.Missing)
      0)
    ((Reading.Value payload)
      payload)))

(test "mutable string local set works"
  (= (swap_string "oak" "slovo") "slovo"))

(test "mutable vec i32 local set works"
  (= (vec_i32_local_value) 41))

(test "mutable vec i64 local set works"
  (= (vec_i64_local_value) 41i64))

(test "mutable vec f64 local set works"
  (= (vec_f64_local_value) 41.0))

(test "mutable vec bool local set works"
  (vec_bool_local_value))

(test "mutable vec string local set works"
  (= (vec_string_local_value) "slovo"))

(test "mutable option i32 local set works"
  (= (option_i32_local_value) 42))

(test "mutable option i64 local set works"
  (= (option_i64_local_value) 42000000000i64))

(test "mutable option f64 local set works"
  (= (option_f64_local_value) 42.5))

(test "mutable option bool local set works"
  (option_bool_local_value))

(test "mutable option string local set works"
  (= (option_string_local_value) "branch"))

(test "mutable result i32 local set works"
  (= (result_i32_local_value) 42))

(test "mutable result i64 local set works"
  (= (result_i64_local_value) 42000000000i64))

(test "mutable result f64 local set works"
  (= (result_f64_local_value) 42.5))

(test "mutable result bool local set works"
  (result_bool_local_value))

(test "mutable result string local set works"
  (= (result_string_local_value) "slovo"))

(test "mutable plain struct local set works"
  (= (point_local_sum) 42))

(test "mutable primitive struct local set works"
  (= (primitive_record_local_label) "beta"))

(test "mutable numeric struct local set works"
  (= (numeric_record_local_ratio) 3.5))

(test "mutable payloadless enum local set works"
  (= (signal_local_code) 3))

(test "mutable payload enum local set works"
  (= (reading_local_code) 42))

(test "mutable enum struct local set works"
  (= (tagged_local_code) 42))

(fn main () -> i32
  (tagged_local_code))
