# 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)) )