diff --git a/assets/prelude.ld b/assets/prelude.ld index 6bd6fae..ee98016 100644 --- a/assets/prelude.ld +++ b/assets/prelude.ld @@ -1039,7 +1039,7 @@ fn self { () -> base :process (:self) } -fn send { +fn send! { "Sends a message to the specified process and returns the message." (pid as :keyword, msg) -> { base :process (:send, pid, msg) @@ -1052,7 +1052,7 @@ fn link! { (pid as :keyword) -> base :process (:link, pid) } -fn spawn! { +fn spawn { "Spawns a process. Takes a 0-argument (nullary) function that will be executed as the new process. Returns a keyword process ID (pid) of the newly spawned process." (f as :fn) -> { let new_pid = base :process (:spawn, f) @@ -1061,7 +1061,7 @@ fn spawn! { } } -fn fledge! { +fn fledge { "Spawns a process and then immediately unlinks from it. Takes a 0-argument (nullary) function that will be executed as the new process. Returns a keyword process ID (pid) of the newly fledged process." (f as :fn) -> base :process (:spawn, f) } @@ -1088,7 +1088,7 @@ fn monitor! { else nil } -fn flush! { +fn flush { "Clears the current process's mailbox and returns all the messages." () -> base :process (:flush) } @@ -1098,7 +1098,7 @@ fn sleep! { (ms as :number) -> base :process (:sleep, ms) } -fn await! { +fn await { "Parks the current process until it receives an exit signal from the passed process. Returns the result of a successful execution or panics if the awaited process panics. If the other process is not alive, returns `nil`." (pid as :keyword) -> if monitor! (pid) then receive { @@ -1127,7 +1127,7 @@ fn hibernate! { () -> receive { _ -> hibernate! () } } -fn heed! { +fn heed { "Parks the current process until it receives a reply, and returns whatever is replied. Causes a panic if it gets anything other than a `(:reply, result)` tuple." () -> receive { (:reply, result) -> result @@ -1164,7 +1164,7 @@ fn request_fetch! { } fn fetch { - "Requests the contents of the URL passed in. Returns a result tuple of `(:ok, {contents})` or `(:err, {status code})`." + "Requests the contents of the URL passed in. Returns a result tuple of (:ok, ) or (:err, )." (url) -> { let pid = self () spawn! (fn () -> request_fetch! (pid, url)) @@ -1402,7 +1402,7 @@ fn turtle_listener () -> { turtle_listener () } -fn spawn_turtle! { +fn spawn_turtle { "Spawns a new turtle in a new process. Methods on the turtle process mirror those of turtle graphics functions in prelude. Returns the pid of the new turtle." () -> { let pid = spawn! (fn () -> turtle_listener ()) @@ -1498,106 +1498,73 @@ fn llist { } &&& keyboard input -fn key_pressed? { +fn key_down? { "Returns true ie the key is currently pressed. Keys are indicated by strings. For non-alphanumeric keys, consult the documentation to get key codes." (key as :string) -> do keys_down > unbox > contains? (key, _) } #{ - & completed actor functions - self - send - spawn! & <- is no longer a special form - yield! - sleep! - alive? - flush! - - & wip actor functions - link! - monitor! - await! - heed! - unlink! - hibernate! - - spawn_turtle! - - key_pressed? - - & shared memory w/ rust - & `box`es are actually way cool - console - input - fetch_outbox + abs & math + add & math + alive? & processes + angle & math + any? & types and values + append & lists + assert! & errors + assoc & dicts + at & tuples, strings, lists + atan/2 & math + await & processes + back! & turtle graphics + background! & turtle graphics + between? & math + bg! & turtle graphics + bk! & turtle graphics + bool & bools + bool? & bools + box? & boxes + butlast & list, tuple, string + car & llist + cdr & llist + ceil & math + chars & strings + clear! & turtle graphics + coll? & dicts, tuples, lists + colors & turtle graphics + colours & turtle graphics + concat & list string + cons & llist + console & buffers + contains? & list, tuple, string + cos & math + count & list, tuple, string + dec & math + deg/rad &math + deg/turn &math + dict & dicts + dict? & dicts + dissoc & dicts + dist & math + div & math + div/0 & math + div/safe & math + doc! & io + downcase & string + each! & list + empty? & list string dict tuple + eq? & values + err & result + err? & result + even? & math + false? & bool + fd! & turtles + fetch & fetch_inbox - keys_down - - & a fetch fn - fetch - & await user input - read_input - - abs - abs - add - angle - any? - append - assert! - assoc - & assoc? - at - atan/2 - back! - background! - between? - bg! - bk! - bool - bool? - box? - butlast - car - cdr - ceil - chars - clear! - coll? - colors - colours - concat - condense - cons - console - contains? - cos - count - dec - deg/rad - deg/turn - dict - dict? - dissoc - dist - div - div/0 - div/safe - doc! - downcase - each! - empty? - eq? - err - err? - even? - false? - fd! + fetch_outbox filter first - first - first floor + flush fn? fold foldr @@ -1609,21 +1576,27 @@ fn key_pressed? { has? heading heading/vector + heed + hibernate! hideturtle! home! inc - indexed? index_of + indexed? indices_of + input inv inv/0 inv/safe join keep + key_down? keys + keys_down keyword? last left! + link! list list? llist @@ -1635,6 +1608,7 @@ fn key_pressed? { mod mod/0 mod/safe + monitor! mult neg neg? @@ -1665,6 +1639,7 @@ fn key_pressed? { random random_int range + read_input report! rest right! @@ -1672,15 +1647,20 @@ fn key_pressed? { round rt! second + self + send! sentence setheading! show showturtle! sin + sleep! slice slice_n some some? + spawn + spawn_turtle split sqrt sqrt/safe @@ -1703,6 +1683,7 @@ fn key_pressed? { turtle_state type unbox + unlink! unwrap! unwrap_or upcase @@ -1711,5 +1692,6 @@ fn key_pressed? { values words ws? + yield! zero? } diff --git a/janet/base.janet b/janet/base.janet index ef68628..db2ad4d 100644 --- a/janet/base.janet +++ b/janet/base.janet @@ -1,7 +1,7 @@ # A base library for Ludus # Only loaded in the prelude -(import /src/scanner :as s) +(import /janet/scanner :as s) (defn bool [x] (if (= :^nil x) nil x)) diff --git a/janet/doc.janet b/janet/doc.janet index 5802a27..a9d5073 100644 --- a/janet/doc.janet +++ b/janet/doc.janet @@ -1,5 +1,5 @@ -(import /src/base :as base) -(import /src/prelude :as prelude) +(import /janet/base :as base) +(import /janet/prelude :as prelude) (defn map-values [f dict] (from-pairs (map (fn [[k v]] [k (f v)]) (pairs dict)))) @@ -23,20 +23,21 @@ (string/join (map toc-entry sorted-names) "    ")) (def topics { - "math" ["abs" "add" "angle" "atan/2" "between?" "ceil" "cos" "dec" "deg/rad" "deg/turn" "dist" "div" "div/0" "div/safe" "even?" "floor" "gt?" "gte?" "heading/vector" "inc" "inv" "inv/0" "inv/safe" "lt?" "lte?" "max" "min" "mod" "mod/0" "mod/safe" "mult" "neg" "neg?" "odd?" "pi" "pos?" "rad/deg" "rad/turn" "random" "random_int" "range" "round" "sin" "sqrt" "sqrt/safe" "square" "sub" "sum_of_squares" "tan" "tau" "to_number" "turn/deg" "turn/rad" "zero?"] - "boolean" ["and" "bool" "bool?" "false?" "not" "or" "true?"] - "dicts" ["any?" "assoc" "assoc?" "coll?" "count" "dict" "dict?" "diff" "dissoc" "empty?" "get" "keys" "random" "update" "values"] - "lists" ["any?" "append" "at" "butlast" "coll?" "concat" "count" "each!" "empty?" "filter" "first" "fold" "join" "keep" "last" "list" "list?" "map" "ordered?" "random" "range" "rest" "second" "sentence" "slice"] + "math" ["abs" "add" "angle" "atan/2" "between?" "ceil" "cos" "dec" "deg/rad" "deg/turn" "dist" "div" "div/0" "div/safe" "even?" "floor" "gt?" "gte?" "heading/vector" "inc" "inv" "inv/0" "inv/safe" "lt?" "lte?" "max" "min" "mod" "mod/0" "mod/safe" "mult" "neg" "neg?" "odd?" "pi" "pos?" "pow" "rad/deg" "rad/turn" "random" "random_int" "range" "round" "sin" "sqrt" "sqrt/safe" "square" "sub" "sum_of_squares" "tan" "tau" "to_number" "turn/deg" "turn/rad" "zero?"] + "bools" ["and" "bool" "bool?" "false?" "not" "or" "true?"] + "dicts" ["any?" "assoc" "coll?" "count" "dict" "dict?" "diff" "dissoc" "empty?" "get" "has?" "keys" "random" "update" "values"] + "lists" ["any?" "append" "at" "butlast" "coll?" "concat" "count" "each!" "empty?" "filter" "first" "fold" "index_of" "indexed?" "indices_of" "join" "keep" "last" "list" "list?" "map" "random" "range" "rest" "second" "sentence" "slice"] "llists" ["car" "cdr" "cons" "llist"] - "sets" ["any?" "append" "coll?" "concat" "contains?" "count" "empty?" "omit" "random" "set" "set?"] + # "sets" ["any?" "append" "coll?" "concat" "contains?" "count" "empty?" "omit" "random" "set" "set?"] "tuples" ["any?" "at" "coll?" "count" "empty?" "first" "last" "ordered?" "rest" "second" "tuple?"] - "strings" ["any?" "chars" "chars/safe" "concat" "count" "downcase" "empty?" "join" "sentence" "show" "slice" "split" "string" "string?" "strip" "to_number" "trim" "upcase" "words"] - "types and values" ["assoc?" "bool?" "box?" "coll?" "dict?" "eq?" "fn?" "keyword?" "list?" "neq?" "nil?" "number?" "ordered?" "set?" "show" "some" "some?" "string?" "tuple?" "type"] - "boxes and state" ["box?" "unbox" "store!" "update!"] + "strings" ["any?" "at" "chars" "chars/safe" "concat" "count" "downcase" "empty?" "join" "sentence" "show" "slice" "slice_n" "split" "string" "string?" "strip" "to_number" "trim" "upcase" "words"] + "types and values" ["bool?" "box?" "coll?" "dict?" "eq?" "fn?" "indexed?" "keyword?" "list?" "nil?" "number?" "set?" "show" "some" "some?" "string?" "tuple?" "type"] + "boxes" ["box?" "unbox" "store!" "update!"] "results" ["err" "err?" "ok" "ok?" "unwrap!" "unwrap_or"] "errors" ["assert!"] - "turtle graphics" ["back!" "background!" "bk!" "clear!" "colors" "fd!" "forward!" "goto!" "heading" "heading/vector" "hideturtle!" "home!" "left!" "loadstate!" "lt!" "pc!" "pd!" "pencolor" "pencolor!" "pendown!" "pendown?" "penup!" "penwidth" "penwidth!" "position" "pu!" "pw!" "render_turtle!" "reset_turtle!" "right!" "rt!" "setheading!" "showturtle!" "turtle_state"] - "environment and i/o" ["doc!" "print!" "report!" "state"] + "turtle graphics" ["back!" "background!" "bk!" "clear!" "colors" "fd!" "forward!" "goto!" "heading" "heading/vector" "hideturtle!" "home!" "left!" "loadstate!" "lt!" "pc!" "pd!" "pencolor" "pencolour" "pencolor!" "pencolour!" "pendown!" "pendown?" "penup!" "penwidth" "penwidth!" "position" "pu!" "pw!" "render_turtle!" "reset_turtle!" "right!" "rt!" "setheading!" "showturtle!" "spawn_turtle" "turtle_state"] + "environment and i/o" ["console" "doc!" "fetch_inbox" "fetch_outbox" "input" "key_down?" "keys_down" "print!" "read_input" "report!"] + "processes" ["alive?" "await" "fledge" "flush" "heed" "hibernate!" "monitor" "self" "send!" "sleep!" "spawn" "unlink!" "yield!"] }) (defn capitalize [str] diff --git a/janet/errors.janet b/janet/errors.janet index 5380409..ce7abc8 100644 --- a/janet/errors.janet +++ b/janet/errors.janet @@ -1,4 +1,4 @@ -(import /src/base :as b) +(import /janet/base :as b) (defn- get-line [source line] ((string/split "\n" source) (dec line))) diff --git a/janet/interpreter.janet b/janet/interpreter.janet index f6a5e53..02c179d 100644 --- a/janet/interpreter.janet +++ b/janet/interpreter.janet @@ -1,6 +1,6 @@ # A tree walk interpreter for ludus -(import /src/base :as b) +(import /janet/base :as b) (var interpret nil) (var match-pattern nil) diff --git a/janet/ludus.janet b/janet/ludus.janet index 72aadef..bb7da3d 100644 --- a/janet/ludus.janet +++ b/janet/ludus.janet @@ -2,14 +2,14 @@ # 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) +(import /janet/scanner :as s) +(import /janet/parser :as p) +(import /janet/validate :as v) +(import /janet/interpreter :as i) +(import /janet/errors :as e) +(import /janet/base :as b) +(import /janet/prelude :as prelude) +(import /janet/json :as j) (defn ludus [source] # if we can't load prelude, bail diff --git a/janet/parser.janet b/janet/parser.janet index edb84d0..97b4cdf 100644 --- a/janet/parser.janet +++ b/janet/parser.janet @@ -1,7 +1,7 @@ ### A recursive descent parser for Ludus ### We still need to scan some things -(import /src/scanner :as s) +(import /janet/scanner :as s) # stash janet type (def janet-type type) @@ -698,6 +698,25 @@ @{:type :match :data [to-match clauses] :token origin}) ([err] err))) +(defn- receive [parser] + (def origin (current parser)) + (def ast {:type :receive :data @[] :token origin}) + (def clauses @[]) + (expect parser :receive) + (advance parser) + (try + (do + (def open-brace (current parser)) + (expect parser :lbrace) (advance parser) + (accept-many parser :newline) + (while (not (check parser :rbrace)) + (when (check parser :eof) + (error {:type :error :token open-brace :msg "unclosed brace"})) + (array/push clauses (match-clause parser))) + (advance parser) + @{:type :receive :data [clauses] :token origin}) + ([err] err))) + # {pattern} = {nonbinding} {terminators} (defn- with-clause [parser] (try @@ -973,7 +992,7 @@ (def body (nonbinding parser)) {:type :test :data [desc body] :token origin}) -### loops and repeates +### loops and repeats (defn- loopp [parser] (def origin (current parser)) (expect parser :loop) (advance parser) @@ -1031,9 +1050,10 @@ :startdict (dict parser) :startset (sett parser) :word (word-expr parser) - :pkg-name (pkg-name parser) + # :pkg-name (pkg-name parser) :recur (recur parser) :panic (panicc parser) + :do (doo parser) (panic parser (string "expected simple expression, got " (type curr))) ) ) @@ -1072,6 +1092,7 @@ :when (whenn parser) :match (matchh parser) :with (withh parser) + :receive (receive parser) # do :do (doo parser) @@ -1114,12 +1135,13 @@ :startdict (dict parser) :startset (sett parser) :word (word-expr parser) - :pkg-name (pkg-name parser) + # :pkg-name (pkg-name parser) :recur (recur parser) :if (iff parser) :when (whenn parser) :match (matchh parser) - :with (withh parser) + :receive (receive parser) + # :with (withh parser) :do (doo parser) :lbrace (block parser) :loop (loopp parser) diff --git a/janet/prelude.janet b/janet/prelude.janet index ef92a71..57a36c0 100644 --- a/janet/prelude.janet +++ b/janet/prelude.janet @@ -1,20 +1,20 @@ -(import /src/base :as b) -(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 /janet/base :as b) +(import /janet/scanner :as s) +(import /janet/parser :as p) +(import /janet/validate :as v) +(import /janet/interpreter :as i) +(import /janet/errors :as e) (def pkg (do (def pre-ctx @{:^parent {"base" b/base}}) - (def pre-src (slurp "../assets/prelude.ld")) + (def pre-src (slurp "./assets/prelude.ld")) (def pre-scanned (s/scan pre-src :prelude)) (def pre-parsed (p/parse pre-scanned)) (def parse-errors (pre-parsed :errors)) (when (any? parse-errors) (each err parse-errors (e/parse-error err)) (break :error)) - (def pre-validated (v/valid pre-parsed pre-ctx)) - (def validation-errors (pre-validated :errors)) - (when (any? validation-errors) (each err validation-errors (e/validation-error err)) (break :error)) + # (def pre-validated (v/valid pre-parsed pre-ctx)) + # (def validation-errors (pre-validated :errors)) + # (when (any? validation-errors) (each err validation-errors (e/validation-error err)) (break :error)) (try (i/interpret (pre-parsed :ast) pre-ctx) ([err] (e/runtime-error err) :error)))) @@ -27,16 +27,16 @@ (set (ctx "^type") nil) ctx)) -(def post/src (slurp "postlude.ld")) +# (def post/src (slurp "postlude.ld")) -(def post/ast (do - (def post-ctx @{:^parent ctx}) - (def post-scanned (s/scan post/src :postlude)) - (def post-parsed (p/parse post-scanned)) - (def parse-errors (post-parsed :errors)) - (when (any? parse-errors) (each err parse-errors (e/parse-error err)) (break :error)) - (def post-validated (v/valid post-parsed post-ctx)) - (def validation-errors (post-validated :errors)) - (when (any? validation-errors) (each err validation-errors (e/validation-error err)) (break :error)) - (post-parsed :ast))) +# (def post/ast (do +# (def post-ctx @{:^parent ctx}) +# (def post-scanned (s/scan post/src :postlude)) +# (def post-parsed (p/parse post-scanned)) +# (def parse-errors (post-parsed :errors)) +# (when (any? parse-errors) (each err parse-errors (e/parse-error err)) (break :error)) +# # (def post-validated (v/valid post-parsed post-ctx)) +# # (def validation-errors (post-validated :errors)) +# # (when (any? validation-errors) (each err validation-errors (e/validation-error err)) (break :error)) +# (post-parsed :ast))) diff --git a/janet/scanner.janet b/janet/scanner.janet index e593728..4c7a801 100644 --- a/janet/scanner.janet +++ b/janet/scanner.janet @@ -9,20 +9,21 @@ "false" :false ## impl -> literal word "fn" :fn ## impl "if" :if ## impl - "import" :import ## impl + # "import" :import ## impl "let" :let ## impl "loop" :loop ## impl "match" :match ## impl "nil" :nil ## impl -> literal word - "ns" :ns ## impl + # "ns" :ns ## impl "panic!" :panic ## impl (should _not_ be a function) - "pkg" :pkg + # "pkg" :pkg + "receive" :receive "recur" :recur ## impl "repeat" :repeat ## impl - "test" :test + # "test" :test "then" :then ## impl "true" :true ## impl -> literal word - "use" :use ## wip + # "use" :use ## wip "when" :when ## impl, replaces cond "with" :with ## impl }) diff --git a/janet/validate.janet b/janet/validate.janet index 88c3501..7cf3e11 100644 --- a/janet/validate.janet +++ b/janet/validate.janet @@ -286,6 +286,13 @@ Deferred until a later iteration of Ludus: (match-clauses validator clauses) validator) +(defn- receive [validator] + (def ast (validator :ast)) + (def [clauses] (ast :data)) + (match-clauses validator clauses) + validator) + + (defn- declare [validator fnn] (def status (validator :status)) (def declared (get status :declared @{})) @@ -758,6 +765,7 @@ Deferred until a later iteration of Ludus: :loop (loopp validator) :recur (recur validator) :box (box validator) + :receive (receive validator) (error (string "unknown node type " type))))) (set validate validate*) diff --git a/justfile b/justfile index baeb882..da2a169 100644 --- a/justfile +++ b/justfile @@ -38,3 +38,8 @@ release: serve: live-server pkg +# build the documentation +doc: + janet janet/doc.janet + -rm doc/prelude.md + mv prelude.md doc/