ludus/src/ludus.janet

107 lines
2.8 KiB
Plaintext
Raw Normal View History

# an integrated Ludus interpreter
2024-06-06 20:14:04 +00:00
# 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]
2024-08-01 22:00:11 +00:00
# if we can't load prelude, bail
(when (= :error prelude/pkg) (error "could not load prelude"))
2024-08-01 22:00:11 +00:00
# get us a clean working slate
2024-06-06 00:16:29 +00:00
(def ctx @{:^parent prelude/ctx})
(def errors @[])
(var result @"")
(def console @"")
2024-08-01 22:00:11 +00:00
# capture all `print`s
2024-06-14 18:53:23 +00:00
(setdyn :out console)
2024-08-01 22:00:11 +00:00
# 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 @[]}}})
2024-08-01 22:00:11 +00:00
### start the program
# first, scanning
(def scanned (s/scan source))
(when (any? (scanned :errors))
(each err (scanned :errors)
2024-06-06 20:14:04 +00:00
(e/scan-error err))
(break (-> out j/encode string)))
2024-08-01 22:00:11 +00:00
# then, parsing
(def parsed (p/parse scanned))
(when (any? (parsed :errors))
2024-06-06 20:14:04 +00:00
(each err (parsed :errors)
(e/parse-error err))
(break (-> out j/encode string)))
2024-08-01 22:00:11 +00:00
# then, validation
2024-06-06 00:16:29 +00:00
(def validated (v/valid parsed ctx))
(when (any? (validated :errors))
2024-06-06 20:14:04 +00:00
(each err (validated :errors)
(e/validation-error err))
2024-06-10 22:26:48 +00:00
(break (-> out j/encode string)))
2024-08-01 22:00:11 +00:00
# and, finally, try interpreting the program
2024-08-01 21:45:09 +00:00
(try (do
2024-08-01 22:00:11 +00:00
# we need to do this every run or we get the very same sequence of "random" numbers every time we run a program
2024-08-01 21:45:09 +00:00
(math/seedrandom (os/cryptorand 8))
(set result (i/interpret (parsed :ast) ctx)))
2024-06-06 20:14:04 +00:00
([err]
(e/runtime-error err)
(break (-> out j/encode string))))
2024-08-01 22:00:11 +00:00
# stop capturing output
2024-06-06 20:14:04 +00:00
(setdyn :out stdout)
2024-08-01 22:00:11 +00:00
# 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]))
2024-08-01 22:00:11 +00:00
# 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
2024-06-06 20:14:04 +00:00
(try
(i/interpret prelude/post/ast ctx)
2024-06-06 20:14:04 +00:00
([err] (e/runtime-error err)))
2024-08-01 22:00:11 +00:00
# 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))
2024-08-01 22:00:11 +00:00
#### REPL
2024-07-20 17:51:11 +00:00
(comment
# (do
2024-07-14 18:28:09 +00:00
# (def start (os/clock))
2024-06-21 19:28:46 +00:00
(def source `
fd! (100)
rt! (0.25)
fd! (100)
lt! (0.25)
fd! (100)
setheading! (0.75)
unbox (turtle_state)
2024-06-21 19:28:46 +00:00
`)
(def out (-> source
ludus
2024-06-24 16:57:09 +00:00
j/decode
2024-06-21 19:28:46 +00:00
))
2024-07-14 18:28:09 +00:00
# (def end (os/clock))
2024-06-21 19:28:46 +00:00
(setdyn :out stdout)
(pp out)
2024-06-24 16:57:09 +00:00
(def console (out "console"))
(print console)
(def result (out "result"))
(print result)
2024-07-14 18:28:09 +00:00
# (print (- end start))
2024-06-10 22:26:48 +00:00
)