Compare commits

..

No commits in common. "68aca09de645a64e8a6131fcfad44b1b5fbf96ea" and "aba77569ac147166bc73415ad65798796f48680a" have entirely different histories.

4 changed files with 305 additions and 736 deletions

View File

@ -18,7 +18,7 @@ fn join
fn neg? fn neg?
fn atan/2 fn atan/2
fn mod fn mod
fn assoc & ? fn assoc?
fn dict fn dict
fn get fn get
fn unbox fn unbox
@ -370,26 +370,14 @@ fn ws? {
(_) -> false (_) -> false
} }
fn strip {
"Removes punctuation from a string, removing all instances of ,.;:?!"
("{x},{y}") -> strip ("{x}{y}")
("{x}.{y}") -> strip ("{x}{y}")
("{x};{y}") -> strip ("{x}{y}")
("{x}:{y}") -> strip ("{x}{y}")
("{x}?{y}") -> strip ("{x}{y}")
("{x}!{y}") -> strip ("{x}{y}")
(x) -> x
}
fn words { fn words {
"Takes a string and returns a list of the words in the string. Strips all whitespace." "Takes a string and returns a list of the words in the string. Strips all whitespace."
(str as :string) -> { (str as :string) -> {
let no_punct = strip (str) let raw_strs = split (str, " ")
let strs = split (no_punct, " ") fn joiner (list, str) -> if eq? (str, "")
fn worder (list, str) -> if empty? (str)
then list then list
else append (list, str) else append (list, str)
fold (worder, strs, []) fold (joiner, raw_strs, [])
} }
} }
@ -514,11 +502,6 @@ fn inv/0 {
(x as :number) -> div/0 (1, x) (x as :number) -> div/0 (1, x)
} }
fn inv/safe {
"Returns the inverse of a number: 1/n or `div/safe (1, n)`. Returns a result tuple."
(x as :number) -> div/safe (1, x)
}
fn abs { fn abs {
"Returns the absolute value of a number." "Returns the absolute value of a number."
(0) -> 0 (0) -> 0
@ -637,13 +620,16 @@ fn max {
& additional list operations now that we have comparitors & additional list operations now that we have comparitors
fn at { fn at {
"Returns the element at index n of a list or tuple, or the byte at index n of a string. Zero-indexed: the first element is at index 0. Returns nil if nothing is found in a list or tuple; returns an empty string if nothing is found in a string." "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) -> base :nth (xs, n) (xs as :list, n as :number) -> when {
(xs as :tuple, n as :number) -> base :nth (n, xs) neg? (n) -> nil
(str as :string, n as :number) -> when { gte? (n, count (xs)) -> nil
neg? (n) -> "" true -> base :nth (n, xs)
gte? (n, count (str)) -> "" }
true -> base :slice (str, n, inc (n)) (xs as :tuple, n as :number) -> when {
neg? (n) -> nil
gte? (n, count (xs)) -> nil
true -> base :nth (n, xs)
} }
(_) -> nil (_) -> nil
} }
@ -755,17 +741,21 @@ fn update {
} }
fn keys { fn keys {
"Takes a dict and returns a list of keys in that dict." "Takes an associative collection and returns a list of keys in that collection. Returns an empty list on anything other than a collection."
(dict as :dict) -> do dict > list > map (first, _) (coll) -> if not (assoc? (coll))
then []
else do coll > list > map (first, _)
} }
fn values { fn values {
"Takes a dict and returns a list of values in that dict." "Takes an associative collection and returns a list of values in that collection. Returns an empty list on anything other than a collection."
(dict) -> do dict > list > map (second, _) (coll) -> if not (assoc? (coll))
then []
else do coll > list > map (second, _)
} }
fn diff { fn diff {
"Takes two dicts and returns a dict describing their differences. Does this shallowly, offering diffs only for keys in the original dict." "Takes two associate data structures and returns a dict describing their differences. Does this shallowly, offering diffs only for keys in the original dict."
(d1 as :dict, d2 as :dict) -> { (d1 as :dict, d2 as :dict) -> {
let key1 = keys (d1) let key1 = keys (d1)
let key2 = keys (d2) let key2 = keys (d2)
@ -792,7 +782,7 @@ fn diff {
} }
fn coll? { fn coll? {
"Returns true if a value is a collection: dict, list, pkg, 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 :list) -> true (coll as :list) -> true
(coll as :tuple) -> true (coll as :tuple) -> true
@ -809,7 +799,7 @@ fn ordered? {
} }
fn assoc? { fn assoc? {
"Returns true if a value is an associative collection: a dict or a pkg." "Returns true if a value is an associative collection: a dict, struct, or namespace."
(assoc as :dict) -> true (assoc as :dict) -> true
(assoc as :pkg) -> true (assoc as :pkg) -> true
(_) -> false (_) -> false
@ -817,10 +807,10 @@ fn assoc? {
& TODO: consider merging `get` and `at` & TODO: consider merging `get` and `at`
fn get { fn get {
"Takes a key, dict, and optional default value; returns the value at key. If the value is not found, returns nil or the default value." "Takes a dict or struct, key, and optional default value; returns the value at key. If the value is not found, returns nil or the default value. Returns nil or default if the first argument is not a dict or struct."
(key as :keyword) -> get (key, _) (key as :keyword) -> get (key, _)
(key as :keyword, dict as :dict) -> get (key, dict) (key as :keyword, coll) -> base :get (key, coll)
(key as :keyword, dict as :dict, default) -> base :get (key, dict, default) (key as :keyword, coll, default) -> base :get (key, coll, default)
} }
& TODO: add sets to this? & TODO: add sets to this?
@ -1348,164 +1338,159 @@ fn penwidth {
box state = nil box state = nil
pkg Prelude { pkg Prelude {
abs & math abs
add & math add
and & bool and
angle & math angle
any? & dicts lists strings sets tuples any?
append & lists sets append
assert! & errors assert!
assoc & dicts assoc
assoc? & dicts assoc?
at & lists strings at
atan/2 & math atan/2
back! & turtles back!
background! & turtles background!
between? & math between?
bg! & turtles bg!
bgcolor & turtles bgcolor
bk! & turtles bk!
bool & bool bool
bool? & bool bool?
box? & boxes box?
butlast & lists strings tuples butlast
ceil & math ceil
clear! & turtles clear!
coll? & dicts lists sets tuples coll?
colors & turtles colors
concat & string list set concat
cos & math cos
count & string list set tuple dict count
dec & math dec
deg/rad & math deg/rad
deg/turn & math deg/turn
dict & dict dict
dict? & dict dict?
diff & dict diff
dissoc & dict dissoc
dist & math dist
div & math div
div/0 & math div/0
div/safe & math div/safe
doc! & env doc!
downcase & string downcase
each! & list each!
empty? & list dict set string tuple empty?
eq? & values eq?
err & result err
err? & result err?
even? & math even?
false? & bool false?
fd! & turtles fd!
filter & list filter
first & list tuple first
floor & math floor
fn? & functions fn?
fold & lists fold
forward! & turtles forward!
get & dicts get
goto! & turtles goto!
gt? & math gt?
gte? & math gte?
heading & turtles heading
heading/vector & math heading/vector
home! & turtles home!
inc & math inc
inv & math inv
inv/0 & math inv/0
inv/safe & math join
join & lists strings keep
keep & lists keys
keys & dicts keyword?
keyword? & keywords last
last & lists tuples left!
left! & turtles list
list & lists load_turtle_state!
list? & lists lt!
load_turtle_state! & turtles lt?
lt! & turtles lte?
lt? & math map
lte? & math max
map & lists min
max & math mod
min & math mult
mod & math neg
mult & math neg?
neg & math neq?
neg? & math nil?
neq? & values not
nil? & nil odd?
not & bool ok
odd? & math ok?
ok & results or
ok? & results ordered?
or & bool p5_calls
ordered? & lists tuples strings pc!
p5_calls & turtles pd!
pc! & turtles pencolor
pd! & turtles pencolor!
pencolor & turtles pendown!
pencolor! & turtles pendown?
pendown! & turtles penup!
pendown? & turtles penwidth
penup! & turtles penwidth!
penwidth & turtles pi
penwidth! & turtles pos?
pi & math position
pos? & math print!
position & turtles prn!
print! & environment pu!
& prn! & environment pw!
pu! & turtles rad/deg
pw! & turtles rad/turn
rad/deg & math random
rad/turn & math random_int
random & math dicts lists tuples sets range
random_int & math render_turtle!
range & math lists report!
render_turtle! & turtles reset_turtle!
report! & environment rest
reset_turtle! & turtles right!
rest & lists tuples round
right! & turtles rt!
round & math second
rt! & turtles set
second & lists tuples set?
sentence & lists strings show
set & sets sin
set? & sets slice
show & strings some
sin & math some?
slice & lists tuples strings split
some & values square
some? & values state
split & strings store!
square & math string
state & environment string?
store! & boxes sub
string & strings sum_of_squares
string? & strings tan
strip & strings tau
sub & math trim
sum_of_squares & math tuple?
tan & math turn/deg
tau & math turn/rad
trim & strings turtle_commands
tuple? & tuples turtle_state
turn/deg & math turtle_states
turn/rad & math type
turtle_commands & turtles unbox
turtle_state & turtles unwrap!
turtle_states & turtles unwrap_or
type & values upcase
unbox & boxes update
unwrap! & results update!
unwrap_or & results values
upcase & strings words
update & dicts zero?
update! & boxes
values & dicts
words & strings lists
ws? & strings
zero? & math
} }

File diff suppressed because one or more lines are too long

View File

@ -130,12 +130,8 @@
(string/join (map (fn [x] (-> x first show-patt)) clauses) "\n")) (string/join (map (fn [x] (-> x first show-patt)) clauses) "\n"))
(defn doc [fnn] (defn doc [fnn]
(when (not= :fn (ludus/type fnn)) (break "No documentation available.")) (def {:name name :doc doc} fnn)
(def {:name name :doc docstring} fnn) (string/join [name (pretty-patterns fnn) doc] "\n"))
(string/join [name
(pretty-patterns fnn)
(if docstring docstring "No docstring available.")]
"\n"))
(defn- conj!-set [sett value] (defn- conj!-set [sett value]
(set (sett value) true) (set (sett value) true)

View File

@ -1,127 +0,0 @@
(import /src/base :as base)
(import /src/prelude :as prelude)
(defn map-values [f dict]
(from-pairs (map (fn [[k v]] [k (f v)]) (pairs dict))))
(def with-docs (map-values base/doc prelude/ctx))
(def sorted-names (-> with-docs keys sort))
(defn escape-underscores [str] (string/replace "_" "\\_" str))
(defn escape-punctuation [str] (->> str
(string/replace "?" "")
(string/replace "!" "")))
(defn toc-entry [name]
(def escaped (escape-underscores name))
(string "[" escaped "](#" (escape-punctuation escaped) ")"))
(def alphabetical-list
(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" "mult" "neg" "neg?" "odd?" "pi" "pos?" "rad/deg" "rad/turn" "random" "random_int" "range" "round" "sin" "square" "sub" "sum_of_squares" "tan" "tau" "turn/deg" "turn/rad" "zero?"]
"boolean" ["and" "bool" "bool?" "false?" "not" "or"]
"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"]
"sets" ["any?" "append" "coll?" "concat" "count" "empty?" "random" "set" "set?"]
"strings" ["any?" "concat" "count" "downcase" "empty?" "join" "sentence" "show" "slice" "split" "string" "string?" "strip" "trim" "upcase" "words"]
"types and values" ["assoc?" "bool?" "coll?" "dict?" "eq?" "fn?" "keyword?" "list?" "neq?" "nil?" "number?" "ordered?" "show" "some" "some?" "string?" "type"]
"boxes and state" ["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" "home!" "left!" "lt!" "pc!" "pd!" "pencolor" "pencolor!" "pendown!" "pendown?" "penup!" "penwidth" "penwidth!" "position" "pu!" "pw!" "render_turtle!" "reset_turtle!" "right!" "rt!" "turtle_state"]
"environment and i/o" ["doc!" "print!" "report!" "state"]
})
(defn capitalize [str]
(def fst (slice str 0 1))
(def rest (slice str 1))
(def init_cap (string/ascii-upper fst))
(def lower_rest (string/ascii-lower rest))
(string init_cap lower_rest))
(defn topic-entry [topic]
(string "### " (capitalize topic) "\n"
(as-> topic _ (topics _) (slice _) (sort _) (map toc-entry _)
(string/join _ "    "))
"\n"))
(def by-topic (let [the-topics (-> topics keys sort)
topics-entries (map topic-entry the-topics)]
(string/join topics-entries "\n")))
(defn compose-entry [name]
(def header (string "### " name "\n"))
(def the-doc (get with-docs name))
(when (= "No documentation available." the-doc)
(break (string header the-doc "\n")))
(def lines (string/split "\n" the-doc))
(def description (last lines))
(def patterns (string/join (slice lines 1 (-> lines length dec)) "\n"))
(string header description "\n```\n" patterns "\n```\n"))
(compose-entry "update")
(def entries (string/join (map compose-entry sorted-names) "\n\n"))
(def doc-file (string
```
# Ludus prelude documentation
These functions are available in every Ludus script.
The documentation for any function can be found within Ludus by passing the function to `doc!`,
e.g., running `doc! (add)` will send the documentation for `add` to the console.
For more information on the syntax & semantics of the Ludus language, see [language.md](./language.md).
## A few notes
**Naming conventions.** Functions whose name ends with a question mark, e.g., `eq?`, return booleans.
Functions whose name ends with an exclamation point, e.g., `make!`, change state in some way.
In other words, they _do things_ rather than _calculating values_.
Functions whose name includes a slash either convert from one value to another, e.g. `deg/rad`,
or they are variations on a function, e.g. `div/0` as a variation on `div`.
**How entries are formatted.** Each entry has a brief (sometimes too brief!) description of what it does.
It is followed by the patterns for each of its function clauses.
This should be enough to indicate order of arguments, types, and so on.
**Patterns often, but do not always, indicate types.** Typed patterns are written as `foo as :bar`,
where the type is indicated by the keyword.
Possible ludus types are: `:nil`, `:boolean`, `:number`, `:keyword` (atomic values);
`:string` (strings are their own beast); `:tuple` and `:list` (indexed collections); `:set` (sets are specific),
`:dict` and `:ns` (associative collections); and `:ref` (references).
**Conventional types.** Ludus has two types based on conventions.
* _Result tuples._ Results are a way of modeling the result of a calculation that might fail.
The two possible values are `(:ok, value)` and `(:err, msg)`.
`msg` is usually a string describing what went wrong.
To work with result tuples, see [`unwrap!`](#unwrap) and [`unwrap_or`](#unwrap_or).
That said, usually you work with these using pattern matching.
* _Vectors._ Vectors are 2-element tuples of x and y coordinates.
The origin is `(0, 0)`.
Many math functions take vectors as well as numbers, e.g., `add` and `mult`.
You will see vectors indicated in patterns by an `(x, y)` tuple.
You can see what this looks like in the last clause of `add`: `((x1, y1), (x2, y2))`.
## Functions by topic
```
by-topic
```
## All functions, alphabetically
```
alphabetical-list
```
## Function documentation
```
entries
))
(spit "prelude.md" doc-file)