prelude now passes validator
This commit is contained in:
parent
5874a56090
commit
20cb689d12
|
@ -44,7 +44,7 @@
|
||||||
:dict (dict-str value)
|
:dict (dict-str value)
|
||||||
:set
|
:set
|
||||||
(string/join (map stringify (keys value)) ", ")
|
(string/join (map stringify (keys value)) ", ")
|
||||||
:ref (stringify (value :^value))
|
:box (stringify (value :^value))
|
||||||
:fn (string "fn " (value :name))
|
:fn (string "fn " (value :name))
|
||||||
:applied (string "fn " (value :name))
|
:applied (string "fn " (value :name))
|
||||||
:function (string "builtin " (string value))
|
:function (string "builtin " (string value))
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
:list (string "[" (stringify x) "]")
|
:list (string "[" (stringify x) "]")
|
||||||
:dict (string "#{" (stringify x) "}")
|
:dict (string "#{" (stringify x) "}")
|
||||||
:set (string "${" (stringify x) "}")
|
:set (string "${" (stringify x) "}")
|
||||||
:ref (string "box " (x :name) " [ " (stringify x) " ]")
|
:box (string "box " (x :name) " [ " (stringify x) " ]")
|
||||||
:pkg (show-pkg x)
|
:pkg (show-pkg x)
|
||||||
(stringify x)))
|
(stringify x)))
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,34 @@
|
||||||
(import spork/json :as j)
|
(import spork/json :as j)
|
||||||
(import /base :as b)
|
(import /base :as b)
|
||||||
|
|
||||||
|
(defn- get-line [source line]
|
||||||
|
((string/split "\n" source) (dec line)))
|
||||||
|
|
||||||
(defn scan-error [e out] (set (out :errors) e) (j/encode out))
|
(defn scan-error [e out] (set (out :errors) e) (j/encode out))
|
||||||
|
|
||||||
(defn parse-error [e out] (set (out :errors) e) (j/encode out))
|
(defn parse-error [e]
|
||||||
|
(def msg (e :msg))
|
||||||
|
(def line-num (get-in e [:token :line]))
|
||||||
|
(def source (get-in e [:token :source]))
|
||||||
|
(def source-line (get-line source line-num))
|
||||||
|
(print "Parsing error: " msg)
|
||||||
|
(print "On line " line-num ":")
|
||||||
|
(print source-line))
|
||||||
|
|
||||||
(defn validation-error [e out] (set (out :errors) e) (j/encode out))
|
|
||||||
|
(defn validation-error [e]
|
||||||
|
(def msg (e :msg))
|
||||||
|
(def line-num (get-in e [:node :token :line]))
|
||||||
|
(def source (get-in e [:node :token :source]))
|
||||||
|
(def source-line (get-line source line-num))
|
||||||
|
(case msg
|
||||||
|
"unbound name"
|
||||||
|
(do
|
||||||
|
(print "Validation error: " msg " " (get-in e [:node :data]))
|
||||||
|
(print "on line " line-num)
|
||||||
|
(print source-line)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
(defn runtime-error [e out] (set (out :errors) e) (j/encode out))
|
(defn runtime-error [e out] (set (out :errors) e) (j/encode out))
|
||||||
|
|
|
@ -340,7 +340,7 @@
|
||||||
(defn- ref [ast ctx]
|
(defn- ref [ast ctx]
|
||||||
(def {:data value-ast :name name} ast)
|
(def {:data value-ast :name name} ast)
|
||||||
(def value (interpret value-ast ctx))
|
(def value (interpret value-ast ctx))
|
||||||
(def box @{:^type :ref :^value value :name name})
|
(def box @{:^type :box :^value value :name name})
|
||||||
(set (ctx name) box)
|
(set (ctx name) box)
|
||||||
box)
|
box)
|
||||||
|
|
||||||
|
|
|
@ -16,16 +16,16 @@ The API from the old Clojure Ludus interpreter returns an object with four field
|
||||||
* `errors`: an array of errors, which are just strings
|
* `errors`: an array of errors, which are just strings
|
||||||
|
|
||||||
This new scene will have to return a JSON POJSO:
|
This new scene will have to return a JSON POJSO:
|
||||||
{:console [...] :result "..." :draw [...] :errors [...]}
|
{:console "..." :result "..." :draw [...] :errors [...]}
|
||||||
)
|
)
|
||||||
|
|
||||||
(def console @"")
|
(def prelude-src (slurp "prelude.ld"))
|
||||||
(setdyn :out console)
|
(def prelude-scanned (s/scan prelude-src))
|
||||||
(print "foo")
|
(def prelude-parsed (p/parse prelude-scanned))
|
||||||
(pp {:a 1 :b 2})
|
(def parse-errors (prelude-parsed :errors))
|
||||||
(setdyn :out stdout)
|
(when (any? parse-errors) (each err parse-errors (e/parse-error err)))
|
||||||
(print "collected out")
|
(def prelude-validated (v/valid prelude-parsed @{"base" b/base}))
|
||||||
(print console)
|
(each err (prelude-validated :errors) (e/validation-error err))
|
||||||
|
|
||||||
(defn run [source]
|
(defn run [source]
|
||||||
(def errors @[])
|
(def errors @[])
|
||||||
|
@ -44,7 +44,7 @@ This new scene will have to return a JSON POJSO:
|
||||||
(break (-> :errors validated (e/validation-error out))))
|
(break (-> :errors validated (e/validation-error out))))
|
||||||
(setdyn :out console)
|
(setdyn :out console)
|
||||||
(try
|
(try
|
||||||
(set result (b/show (i/interpret (parsed :ast) @{})))
|
(set result (b/show (i/interpret (parsed :ast) @{:^parent b/base})))
|
||||||
([err] (e/runtime-error err out)))
|
([err] (e/runtime-error err out)))
|
||||||
(set (out :result) result)
|
(set (out :result) result)
|
||||||
(j/encode out))
|
(j/encode out))
|
||||||
|
@ -56,8 +56,8 @@ This new scene will have to return a JSON POJSO:
|
||||||
(run source))
|
(run source))
|
||||||
|
|
||||||
(def source `
|
(def source `
|
||||||
fn foo () -> :foo
|
let foo = fn () -> :bar
|
||||||
foo ()
|
foo ()
|
||||||
`)
|
`)
|
||||||
|
|
||||||
(-> source run j/decode)
|
(-> source run j/decode)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
### A recursive descent parser for Ludus
|
### A recursive descent parser for Ludus
|
||||||
|
|
||||||
### We still need to scan some things
|
### We still need to scan some things
|
||||||
# (try (os/cd "janet") ([_] nil)) # when in repl to do relative imports
|
(try (os/cd "janet") ([_] nil)) # when in repl to do relative imports
|
||||||
(import ./scanner :as s)
|
(import ./scanner :as s)
|
||||||
|
|
||||||
(defmacro declare
|
(defmacro declare
|
||||||
|
@ -773,7 +773,7 @@
|
||||||
(defn- lambda [parser]
|
(defn- lambda [parser]
|
||||||
(def origin (current parser))
|
(def origin (current parser))
|
||||||
(expect parser :fn) (advance parser)
|
(expect parser :fn) (advance parser)
|
||||||
@{:type :fn :data (fn-simple parser) :token origin})
|
@{:type :fn :data ((fn-simple parser) :clauses) :token origin})
|
||||||
|
|
||||||
(defn- fnn [parser]
|
(defn- fnn [parser]
|
||||||
(if (= :lparen (-> parser peek type)) (break (lambda parser)))
|
(if (= :lparen (-> parser peek type)) (break (lambda parser)))
|
||||||
|
@ -1104,6 +1104,7 @@
|
||||||
(def origin (current parser))
|
(def origin (current parser))
|
||||||
(def lines @[])
|
(def lines @[])
|
||||||
(while (not (check parser :eof))
|
(while (not (check parser :eof))
|
||||||
|
(accept-many parser :newline)
|
||||||
(array/push lines (capture toplevel parser))
|
(array/push lines (capture toplevel parser))
|
||||||
(capture terminator parser))
|
(capture terminator parser))
|
||||||
{:type :script :data lines :token origin})
|
{:type :script :data lines :token origin})
|
||||||
|
@ -1116,10 +1117,10 @@
|
||||||
|
|
||||||
# (do
|
# (do
|
||||||
(comment
|
(comment
|
||||||
(def source `pkg Foo {}
|
(def source `fn () -> 42
|
||||||
`)
|
`)
|
||||||
(def scanned (s/scan source))
|
(def scanned (s/scan source))
|
||||||
# (print "\n***NEW PARSE***\n")
|
# (print "\n***NEW PARSE***\n")
|
||||||
(def a-parser (new-parser scanned))
|
(def a-parser (new-parser scanned))
|
||||||
(def parsed (pkg a-parser))
|
(def parsed (fnn a-parser))
|
||||||
)
|
)
|
||||||
|
|
273
janet/prelude.ld
273
janet/prelude.ld
|
@ -7,6 +7,29 @@
|
||||||
& tuple?
|
& tuple?
|
||||||
& ref?
|
& ref?
|
||||||
|
|
||||||
|
& some forward declarations
|
||||||
|
& TODO: fix this so that we don't need (as many of) them
|
||||||
|
fn first
|
||||||
|
fn append
|
||||||
|
fn some?
|
||||||
|
fn update!
|
||||||
|
fn string
|
||||||
|
fn join
|
||||||
|
fn neg?
|
||||||
|
fn atan/2
|
||||||
|
fn mod
|
||||||
|
fn assoc?
|
||||||
|
fn dict
|
||||||
|
fn get
|
||||||
|
fn unbox
|
||||||
|
fn store!
|
||||||
|
fn turn/rad
|
||||||
|
fn deg/rad
|
||||||
|
fn floor
|
||||||
|
fn and
|
||||||
|
fn apply_command
|
||||||
|
fn state/call
|
||||||
|
|
||||||
& the very base: know something's type
|
& the very base: know something's type
|
||||||
fn type {
|
fn type {
|
||||||
"Returns a keyword representing the type of the value passed in."
|
"Returns a keyword representing the type of the value passed in."
|
||||||
|
@ -28,6 +51,40 @@ fn eq? {
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&&& true & false: boolean logic (part the first)
|
||||||
|
fn bool? {
|
||||||
|
"Returns true if a value is of type :boolean."
|
||||||
|
(false) -> true
|
||||||
|
(true) -> true
|
||||||
|
(_) -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn true? {
|
||||||
|
"Returns true if a value is boolean `true`. Useful to distinguish between `true` and anything else."
|
||||||
|
(true) -> true
|
||||||
|
(_) -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn false? {
|
||||||
|
"Returns `true` if a value is `false`, otherwise returns `false`. Useful to distinguish between `false` and `nil`."
|
||||||
|
(false) -> true
|
||||||
|
(_) -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool {
|
||||||
|
"Returns false if a value is nil or false, otherwise returns true."
|
||||||
|
(nil) -> false
|
||||||
|
(false) -> false
|
||||||
|
(_) -> true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn not {
|
||||||
|
"Returns false if a value is truthy, true if a value is falsy."
|
||||||
|
(nil) -> true
|
||||||
|
(false) -> true
|
||||||
|
(_) -> false
|
||||||
|
}
|
||||||
|
|
||||||
fn neq? {
|
fn neq? {
|
||||||
"Returns true if none of the arguments have the same value."
|
"Returns true if none of the arguments have the same value."
|
||||||
(x) -> false
|
(x) -> false
|
||||||
|
@ -73,55 +130,6 @@ fn dec {
|
||||||
(x as :number) -> base :dec (x)
|
(x as :number) -> base :dec (x)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn at {
|
|
||||||
"Returns the element at index n of a list or tuple. Zero-indexed: the first element is at index 0."
|
|
||||||
(xs as :list, n as :number) -> when {
|
|
||||||
neg? (n) -> nil
|
|
||||||
gte? (n, count (xs)) -> nil
|
|
||||||
else -> base :nth (xs, inc (n))
|
|
||||||
}
|
|
||||||
(xs as :tuple, n as :number) -> when {
|
|
||||||
neg? (n) -> nil
|
|
||||||
gte? (n, count (xs)) -> nil
|
|
||||||
else -> base :nth (xs, inc (n))
|
|
||||||
}
|
|
||||||
(_) -> nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fn first {
|
|
||||||
"Returns the first element of a list or tuple."
|
|
||||||
(xs) -> at (xs, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn second {
|
|
||||||
"Returns the second element of a list or tuple."
|
|
||||||
(xs) -> at (xs, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn last {
|
|
||||||
"Returns the last element of a list or tuple."
|
|
||||||
(xs) -> at (xs, sub (count (xs), 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn butlast {
|
|
||||||
"Returns a list, omitting the last element."
|
|
||||||
(xs as :list) -> base :slice (xs, sub (count (xs), 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn slice {
|
|
||||||
"Returns a slice of a list, representing a sub-list."
|
|
||||||
(xs as :list, end as :number) -> slice (xs, 0, end)
|
|
||||||
(xs as :list, start as :number, end as :number) -> when {
|
|
||||||
gte? (start, end) -> []
|
|
||||||
gt? (end, count (xs)) -> slice (xs, start, count (xs))
|
|
||||||
neg? (start) -> slice (xs, 0, end)
|
|
||||||
else -> {
|
|
||||||
let slice = base :slice (xs, inc (start), inc (end))
|
|
||||||
base :into ([], slice)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn count {
|
fn count {
|
||||||
"Returns the number of elements in a collection (including string)."
|
"Returns the number of elements in a collection (including string)."
|
||||||
(xs as :list) -> dec (base :count (xs))
|
(xs as :list) -> dec (base :count (xs))
|
||||||
|
@ -142,6 +150,16 @@ fn empty? {
|
||||||
(_) -> false
|
(_) -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn any? {
|
||||||
|
"Returns true if something is not empty, otherwise returns false (including for things that can't be logically full, like numbers)."
|
||||||
|
([...]) -> true
|
||||||
|
(#{...}) -> true
|
||||||
|
(s as :set) -> not (empty? (s))
|
||||||
|
((...)) -> true
|
||||||
|
(s as :string) -> not (empty? (s))
|
||||||
|
(_) -> false
|
||||||
|
}
|
||||||
|
|
||||||
fn list? {
|
fn list? {
|
||||||
"Returns true if the value is a list."
|
"Returns true if the value is a list."
|
||||||
(l as :list) -> true
|
(l as :list) -> true
|
||||||
|
@ -153,6 +171,7 @@ fn list {
|
||||||
(x) -> base :to_list (x)
|
(x) -> base :to_list (x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& TODO: make this work with Janet base
|
||||||
fn set {
|
fn set {
|
||||||
"Takes an ordered collection--list or tuple--and turns it into a set."
|
"Takes an ordered collection--list or tuple--and turns it into a set."
|
||||||
(xs as :list) -> base :into (${}, xs)
|
(xs as :list) -> base :into (${}, xs)
|
||||||
|
@ -180,6 +199,7 @@ fn fold {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& TODO: optimize these with base :conj!
|
||||||
fn map {
|
fn map {
|
||||||
"Maps a function over a list: returns a new list with elements that are the result of applying the function to each element in the original list. E.g., `map ([1, 2, 3], inc) &=> [2, 3, 4]`."
|
"Maps a function over a list: returns a new list with elements that are the result of applying the function to each element in the original list. E.g., `map ([1, 2, 3], inc) &=> [2, 3, 4]`."
|
||||||
(f as :fn, xs) -> {
|
(f as :fn, xs) -> {
|
||||||
|
@ -227,13 +247,13 @@ fn concat {
|
||||||
& the console: sending messages to the outside world
|
& the console: sending messages to the outside world
|
||||||
& the console is *both* something we send to the host language's console
|
& the console is *both* something we send to the host language's console
|
||||||
& ...and also a list of messages.
|
& ...and also a list of messages.
|
||||||
ref console = []
|
box console = []
|
||||||
|
|
||||||
fn flush! {
|
fn flush! {
|
||||||
"Clears the console, and returns the messages."
|
"Clears the console, and returns the messages."
|
||||||
() -> {
|
() -> {
|
||||||
let msgs = deref (console)
|
let msgs = unbox (console)
|
||||||
make! (console, [])
|
store! (console, [])
|
||||||
msgs
|
msgs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,28 +340,28 @@ fn join {
|
||||||
|
|
||||||
&&& references: mutable state and state changes
|
&&& references: mutable state and state changes
|
||||||
|
|
||||||
fn ref? {
|
fn box? {
|
||||||
"Returns true if a value is a ref."
|
"Returns true if a value is a box."
|
||||||
(r as :ref) -> true
|
(b as :box) -> true
|
||||||
(_) -> false
|
(_) -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deref {
|
fn unbox {
|
||||||
"Resolves a ref into a value."
|
"Returns the value that is stored in a box."
|
||||||
(r as :ref) -> base :deref (r)
|
(b as :box) -> base :unbox (b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make! {
|
fn store! {
|
||||||
"Sets the value of a ref."
|
"Stores a value in a box, replacing the value that was previously there. Returns the value."
|
||||||
(r as :ref, value) -> base :set! (r, value)
|
(b as :box, value) -> base :set! (b, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update! {
|
fn update! {
|
||||||
"Updates a ref by applying a function to its value. Returns the new value."
|
"Updates a box by applying a function to its value. Returns the new value."
|
||||||
(r as :ref, f as :fn) -> {
|
(b as :box, f as :fn) -> {
|
||||||
let current = deref (r)
|
let current = unbox (b)
|
||||||
let new = f (current)
|
let new = f (current)
|
||||||
make! (r, new)
|
store! (b, new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,6 +561,56 @@ fn max {
|
||||||
(x, y, ...zs) -> fold (max, zs, max (x, y))
|
(x, y, ...zs) -> fold (max, zs, max (x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& additional list operations now that we have comparitors
|
||||||
|
fn at {
|
||||||
|
"Returns the element at index n of a list or tuple. Zero-indexed: the first element is at index 0."
|
||||||
|
(xs as :list, n as :number) -> when {
|
||||||
|
neg? (n) -> nil
|
||||||
|
gte? (n, count (xs)) -> nil
|
||||||
|
true -> base :nth (xs, inc (n))
|
||||||
|
}
|
||||||
|
(xs as :tuple, n as :number) -> when {
|
||||||
|
neg? (n) -> nil
|
||||||
|
gte? (n, count (xs)) -> nil
|
||||||
|
true -> base :nth (xs, inc (n))
|
||||||
|
}
|
||||||
|
(_) -> nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first {
|
||||||
|
"Returns the first element of a list or tuple."
|
||||||
|
(xs) -> at (xs, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn second {
|
||||||
|
"Returns the second element of a list or tuple."
|
||||||
|
(xs) -> at (xs, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last {
|
||||||
|
"Returns the last element of a list or tuple."
|
||||||
|
(xs) -> at (xs, dec (count (xs)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn butlast {
|
||||||
|
"Returns a list, omitting the last element."
|
||||||
|
(xs as :list) -> base :slice (xs, dec (count (xs)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slice {
|
||||||
|
"Returns a slice of a list, representing a sub-list."
|
||||||
|
(xs as :list, end as :number) -> slice (xs, 0, end)
|
||||||
|
(xs as :list, start as :number, end as :number) -> when {
|
||||||
|
gte? (start, end) -> []
|
||||||
|
gt? (end, count (xs)) -> slice (xs, start, count (xs))
|
||||||
|
neg? (start) -> slice (xs, 0, end)
|
||||||
|
true -> {
|
||||||
|
let slice = base :slice (xs, inc (start), inc (end))
|
||||||
|
base :into ([], slice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&&& keywords: funny names
|
&&& keywords: funny names
|
||||||
fn keyword? {
|
fn keyword? {
|
||||||
"Returns true if a value is a keyword, otherwise returns false."
|
"Returns true if a value is a keyword, otherwise returns false."
|
||||||
|
@ -570,40 +640,6 @@ fn some {
|
||||||
(value, _) -> value
|
(value, _) -> value
|
||||||
}
|
}
|
||||||
|
|
||||||
&&& true & false: boolean logic
|
|
||||||
|
|
||||||
fn bool? {
|
|
||||||
"Returns true if a value is of type :boolean."
|
|
||||||
(false) -> true
|
|
||||||
(true) -> true
|
|
||||||
(_) -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn true? {
|
|
||||||
"Returns true if a value is boolean `true`. Useful to distinguish between `true` and anything else."
|
|
||||||
(true) -> true
|
|
||||||
(_) -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn false? {
|
|
||||||
"Returns `true` if a value is `false`, otherwise returns `false`. Useful to distinguish between `false` and `nil`."
|
|
||||||
(false) -> true
|
|
||||||
(_) -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bool {
|
|
||||||
"Returns false if a value is nil or false, otherwise returns true."
|
|
||||||
(nil) -> false
|
|
||||||
(false) -> false
|
|
||||||
(_) -> true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn not {
|
|
||||||
"Returns false if a value is truthy, true if a value is falsy."
|
|
||||||
(nil) -> true
|
|
||||||
(false) -> true
|
|
||||||
(_) -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
& TODO: make `and` and `or` special forms which lazily evaluate arguments
|
& TODO: make `and` and `or` special forms which lazily evaluate arguments
|
||||||
fn and {
|
fn and {
|
||||||
|
@ -689,7 +725,6 @@ fn diff {
|
||||||
fn coll? {
|
fn coll? {
|
||||||
"Returns true if a value is a collection: dict, struct, list, tuple, or set."
|
"Returns true if a value is a collection: dict, struct, list, tuple, or set."
|
||||||
(coll as :dict) -> true
|
(coll as :dict) -> true
|
||||||
(coll as :struct) -> true
|
|
||||||
(coll as :list) -> true
|
(coll as :list) -> true
|
||||||
(coll as :tuple) -> true
|
(coll as :tuple) -> true
|
||||||
(coll as :set) -> true
|
(coll as :set) -> true
|
||||||
|
@ -988,29 +1023,29 @@ let turtle_init = #{
|
||||||
|
|
||||||
& turtle states: refs that get modified by calls
|
& turtle states: refs that get modified by calls
|
||||||
& turtle_commands is a list of commands, expressed as tuples
|
& turtle_commands is a list of commands, expressed as tuples
|
||||||
ref turtle_commands = []
|
box turtle_commands = []
|
||||||
|
|
||||||
& and a list of turtle states
|
& and a list of turtle states
|
||||||
ref turtle_states = [turtle_init]
|
box turtle_states = [turtle_init]
|
||||||
|
|
||||||
fn reset_turtle! {
|
fn reset_turtle! {
|
||||||
"Resets the turtle to its original state."
|
"Resets the turtle to its original state."
|
||||||
() -> make! (turtle_states, [turtle_init])
|
() -> store! (turtle_states, [turtle_init])
|
||||||
}
|
}
|
||||||
|
|
||||||
& and a list of calls to p5--at least for now
|
& and a list of calls to p5--at least for now
|
||||||
ref p5_calls = []
|
box p5_calls = []
|
||||||
|
|
||||||
& ...and finally, a background color
|
& ...and finally, a background color
|
||||||
& we need to store this separately because, while it can be updated later,
|
& we need to store this separately because, while it can be updated later,
|
||||||
& it must be the first call to p5.
|
& it must be the first call to p5.
|
||||||
ref bgcolor = colors :black
|
box bgcolor = colors :black
|
||||||
|
|
||||||
fn add_call! (call) -> update! (p5_calls, append (_, call))
|
fn add_call! (call) -> update! (p5_calls, append (_, call))
|
||||||
|
|
||||||
fn add_command! (command) -> {
|
fn add_command! (command) -> {
|
||||||
update! (turtle_commands, append (_, command))
|
update! (turtle_commands, append (_, command))
|
||||||
let prev = do turtle_states > deref > last
|
let prev = do turtle_states > unbox > last
|
||||||
let curr = apply_command (prev, command)
|
let curr = apply_command (prev, command)
|
||||||
update! (turtle_states, append (_, curr))
|
update! (turtle_states, append (_, curr))
|
||||||
let call = state/call ()
|
let call = state/call ()
|
||||||
|
@ -1026,7 +1061,7 @@ let turtle_angle = 0.385
|
||||||
let turtle_color = (255, 255, 255, 150)
|
let turtle_color = (255, 255, 255, 150)
|
||||||
|
|
||||||
fn render_turtle! () -> {
|
fn render_turtle! () -> {
|
||||||
let state = do turtle_states > deref > last
|
let state = do turtle_states > unbox > last
|
||||||
if state :visible?
|
if state :visible?
|
||||||
then {
|
then {
|
||||||
let (r, g, b, a) = turtle_color
|
let (r, g, b, a) = turtle_color
|
||||||
|
@ -1055,8 +1090,8 @@ fn render_turtle! () -> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state/call () -> {
|
fn state/call () -> {
|
||||||
let cmd = do turtle_commands > deref > last > first
|
let cmd = do turtle_commands > unbox > last > first
|
||||||
let states = deref (turtle_states)
|
let states = unbox (turtle_states)
|
||||||
let curr = last (states)
|
let curr = last (states)
|
||||||
let prev = at (states, sub (count (states), 2))
|
let prev = at (states, sub (count (states), 2))
|
||||||
match cmd with {
|
match cmd with {
|
||||||
|
@ -1078,7 +1113,7 @@ fn state/call () -> {
|
||||||
(:stroke, r, g, b, a)
|
(:stroke, r, g, b, a)
|
||||||
}
|
}
|
||||||
:clear -> (:background, 0, 0, 0, 255)
|
:clear -> (:background, 0, 0, 0, 255)
|
||||||
else -> nil
|
_ -> nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1144,9 +1179,9 @@ let pw! = penwidth!
|
||||||
|
|
||||||
fn background! {
|
fn background! {
|
||||||
"Sets the background color behind the turtle and path. Alias: bg!"
|
"Sets the background color behind the turtle and path. Alias: bg!"
|
||||||
(gray as :number) -> make! (bgcolor, (gray, gray, gray, 255))
|
(gray as :number) -> store! (bgcolor, (gray, gray, gray, 255))
|
||||||
((r as :number, g as :number, b as :number)) -> make! (bgcolor, (r, b, g, 255))
|
((r as :number, g as :number, b as :number)) -> store! (bgcolor, (r, b, g, 255))
|
||||||
((r as :number, g as :number, b as :number, a as :number)) -> make! (bgcolor, (r, g, b, a))
|
((r as :number, g as :number, b as :number, a as :number)) -> store! (bgcolor, (r, g, b, a))
|
||||||
}
|
}
|
||||||
|
|
||||||
let bg! = background!
|
let bg! = background!
|
||||||
|
@ -1205,7 +1240,7 @@ fn apply_command {
|
||||||
|
|
||||||
fn turtle_state {
|
fn turtle_state {
|
||||||
"Returns the turtle's current state."
|
"Returns the turtle's current state."
|
||||||
() -> do turtle_states > deref > last
|
() -> do turtle_states > unbox > last
|
||||||
}
|
}
|
||||||
|
|
||||||
& position () -> (x, y)
|
& position () -> (x, y)
|
||||||
|
@ -1234,12 +1269,14 @@ fn penwidth {
|
||||||
() -> turtle_state () :pencolor
|
() -> turtle_state () :pencolor
|
||||||
}
|
}
|
||||||
|
|
||||||
ns prelude {
|
pkg Prelude {
|
||||||
type
|
type
|
||||||
eq?
|
eq?
|
||||||
neq?
|
neq?
|
||||||
tuple?
|
tuple?
|
||||||
fn?
|
fn?
|
||||||
|
empty?
|
||||||
|
any?
|
||||||
first
|
first
|
||||||
second
|
second
|
||||||
rest
|
rest
|
||||||
|
@ -1266,9 +1303,9 @@ ns prelude {
|
||||||
report!
|
report!
|
||||||
doc!
|
doc!
|
||||||
concat
|
concat
|
||||||
ref?
|
box?
|
||||||
deref
|
unbox
|
||||||
make!
|
store!
|
||||||
update!
|
update!
|
||||||
string
|
string
|
||||||
string?
|
string?
|
||||||
|
|
|
@ -173,7 +173,7 @@ Deferred until a later iteration of Ludus:
|
||||||
:dict
|
:dict
|
||||||
:list
|
:list
|
||||||
:fn
|
:fn
|
||||||
:ref
|
:box
|
||||||
:pkg
|
:pkg
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -296,7 +296,7 @@ Deferred until a later iteration of Ludus:
|
||||||
(defn- fnn [validator]
|
(defn- fnn [validator]
|
||||||
(def ast (validator :ast))
|
(def ast (validator :ast))
|
||||||
(def name (ast :name))
|
(def name (ast :name))
|
||||||
# (print "function name: " name)
|
(print "function name: " name)
|
||||||
(def status (validator :status))
|
(def status (validator :status))
|
||||||
(def tail? (status :tail))
|
(def tail? (status :tail))
|
||||||
(set (status :tail) true)
|
(set (status :tail) true)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user