import {
    fmt
    runtime
    streams
}

def Main(start any) (stop any) {
    map streams.Map<int, any>{FizzBuzz}
    for_each streams.ForEach<any>{fmt.Println<any>}
    range streams.Range
    wait streams.Wait
    panic runtime.Panic
    ---
    :start -> [
        1 -> range:from,
        101 -> range:to
    ]
    range -> map -> for_each
    for_each:res -> wait -> :stop
    for_each:err -> panic
}

def FizzBuzz(data int) (res any) {
    select Select<any>
    mod15 Mod15
    mod3 Mod3
    mod5 Mod5

    ---

    :data -> [
        mod15,
        select:then[3],
        'FizzBuzz' -> select:then[0],
        'Fizz' -> select:then[1],
        'Buzz' -> select:then[2]
    ]

    mod15:then -> select:if[0]
    mod15:else -> mod3

    mod3:then -> select:if[1]
    mod3:else -> mod5

    mod5:then -> select:if[2]
    mod5:else -> select:if[3]

    select -> :res
}

def Mod15(num int) (then int, else int) {
    h ModHelper
    ---
    :num -> [h:num, 15 -> h:den]
    h:then -> :then
    h:else -> :else
}

def Mod3(num int) (then int, else int) {
    h ModHelper
    ---
    :num -> [h:num, 3 -> h:den]
    h:then -> :then
    h:else -> :else
}

def Mod5(num int) (then int, else int) {
    h ModHelper
    ---
    :num -> [h:num, 5 -> h:den]
    h:then -> :then
    h:else -> :else
}

def ModHelper(num int, den int) (then int, else int) {
    mod Mod
    cond Cond<int>
    eq Eq<int>
    ---
    :num -> [mod:left, cond:data]
    :den -> mod:right

    mod -> [eq:left, 0 -> eq:right]
    eq -> cond:if

    cond:then -> :then
    cond:else -> :else
}
