; Bench fixture (Bench iter): linked-list build + sum.
;
; Drives the heap allocator hard via a recursive Cons spine. Every
; ICons cell is one allocation (24 bytes: tag + Int payload + tail).
; A list of length N therefore costs N allocations. We invoke the
; workload at three different sizes within a single program run to
; cover small / medium / large territory.
;
; Both `cons_n` (build) and `sum_list` (traverse) are written in
; accumulator form so the recursive call sits in tail position and
; can be marked `tail-app`. This is essential at the sizes used here:
; without `musttail`, three million stack frames overflow the default
; thread stack and segfault.
;
; Workload sizes (hardcoded — AILang has no env-var/argv pipeline):
;
;   100_000   * 24 B =   2.4 MB
;   1_000_000 * 24 B =  24   MB
;   3_000_000 * 24 B =  72   MB
;
; (3M was chosen as the largest size that comfortably fits inside the
; bump allocator's 256 MB arena with headroom for closure pairs and
; misc allocations.)
;
; Build is allocation-heavy; sum is pure traversal of already-allocated
; heap (the interesting one for GC pressure / barrier overhead).
;
; Expected stdout (one int per line, the sum 0+1+...+(N-1) = N*(N-1)/2):
;   100_000   -> 4999950000
;   1_000_000 -> 499999500000
;   3_000_000 -> 4499998500000

(module bench_list_sum

  (data IntList
    (ctor INil)
    (ctor ICons (con Int) (con IntList)))

  (fn cons_n_acc
    (doc "Tail-recursive list builder. Result = accumulator-prepended list.")
    (type
      (fn-type
        (params (con Int) (con IntList))
        (ret (con IntList))))
    (params n acc)
    (body
      (if (app == n 0)
        acc
        (tail-app cons_n_acc
          (app - n 1)
          (term-ctor IntList ICons (app - n 1) acc)))))

  (fn cons_n
    (doc "Build [0, 1, ..., n-1] :: IntList. Order doesn't matter for sum.")
    (type
      (fn-type
        (params (con Int))
        (ret (con IntList))))
    (params n)
    (body
      (app cons_n_acc n (term-ctor IntList INil))))

  (fn sum_acc
    (doc "Tail-recursive sum.")
    (type
      (fn-type
        (params (con IntList) (con Int))
        (ret (con Int))))
    (params xs acc)
    (body
      (match xs
        (case (pat-ctor INil) acc)
        (case (pat-ctor ICons h t)
          (tail-app sum_acc t (app + acc h))))))

  (fn sum_list
    (doc "Sum every element. Calls sum_acc with seed 0.")
    (type
      (fn-type
        (params (con IntList))
        (ret (con Int))))
    (params xs)
    (body
      (app sum_acc xs 0)))

  (fn run_one
    (doc "Build a list of length n, sum it, print the sum.")
    (type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
    (params n)
    (body
      (do io/print_int (app sum_list (app cons_n n)))))

  (fn main
    (type (fn-type (params) (ret (con Unit)) (effects IO)))
    (params)
    (body
      (seq (app run_one 100000)
      (seq (app run_one 1000000)
           (app run_one 3000000))))))
