# an integrated Ludus interpreter
# devised in order to run under wasm
# takes a string, returns a string with a json object
# (try (os/cd "janet") ([_] nil)) # for REPL
(import /src/scanner :as s)
(import /src/parser :as p)
(import /src/validate :as v)
(import /src/interpreter :as i)
(import /src/errors :as e)
(import /src/base :as b)
(import /src/prelude :as prelude)
(import /src/json :as j)

(defn ludus [source]
 # if we can't load prelude, bail
 (when (= :error prelude/pkg) (error "could not load prelude"))

 # get us a clean working slate
 (def ctx @{:^parent prelude/ctx})
 (def errors @[])
 (var result @"")
 (def console @"")

 # capture all `print`s
 (setdyn :out console)

 # an output table
 # this will change: the shape of our output
 # at the moment, there's only one stack of turtle graphics
 # we will be getting more
 (def out @{:errors errors :result result 
  :io @{
   :stdout @{:proto [:text-stream "0.1.0"] :data console} 
   :turtle @{:proto [:turtle-graphics "0.1.0"] :data @[]}}})

 ### start the program
 # first, scanning
 (def scanned (s/scan source))
 (when (any? (scanned :errors))
   (each err (scanned :errors)
    (e/scan-error err))
   (break (-> out j/encode string)))
 # then, parsing
 (def parsed (p/parse scanned))
 (when (any? (parsed :errors))
  (each err (parsed :errors)
   (e/parse-error err))
  (break (-> out j/encode string)))
 # then, validation
 (def validated (v/valid parsed ctx))
 (when (any? (validated :errors))
  (each err (validated :errors)
   (e/validation-error err))
  (break (-> out j/encode string)))
 # and, finally, try interpreting the program
 (try (do
  # we need to do this every run or we get the very same sequence of "random" numbers every time we run a program
  (math/seedrandom (os/cryptorand 8))
  (set result (i/interpret (parsed :ast) ctx)))
  ([err] 
   (e/runtime-error err)
   (break (-> out j/encode string))))

 # stop capturing output
 (setdyn :out stdout)

 # update our output table with our output
 (set (out :result) (b/show result))
 (set (((out :io) :turtle) :data) (get-in prelude/pkg [:turtle_commands :^value]))

 # run the "postlude": any Ludus code that needs to run after each program
 # right now this is just resetting the boxes that hold turtle commands and state
 (try
  (i/interpret prelude/post/ast ctx)
  ([err] (e/runtime-error err)))

 # json-encode our output table, and convert it from a buffer to a string (which we require for playing nice with WASM/C)
 (-> out j/encode string))

#### REPL
(comment
# (do
 # (def start (os/clock))
 (def source `
fd! (100)
rt! (0.25)
fd! (100)
lt! (0.25)
fd! (100)
setheading! (0.75)
unbox (turtle_state)
 `)
 (def out (-> source 
  ludus
  j/decode
  ))
 # (def end (os/clock))
 (setdyn :out stdout)
 (pp out)
 (def console (out "console"))
 (print console)
 (def result (out "result"))
 (print result)
 # (print (- end start))
)

