Welcome
This is a real shell and scripting language that at least two people really use each day. They really use it on the CLI and they really use it to write scripts because they want to use a real language in the terminal and they want that same language to be available for scripting. There's one huge and wonderful catch, it's a lisp!
As a shell
As a shell slosh does not differ much from bash at all. It supports pipes, redirects, ... etc. You could replace your grandmother's shell with slosh and as long as you ported her prompt verbatim she probably would not notice.
As a language
Slosh is inspired by clojure and scheme. It is a type 1 lisp.
Motivation
Lisp is a truly novel family of languages. Every year new developers discover what many people have discovered long before them.
Some of them go on to realize that using a lisp regularly in the terminal could not only enhance their skills as a developer but potentially open them up to a whole world of automation and fun by interacting with software that sparks joy. This could result in a renaissance of custom functionality spread lovingly throughout their systems. Despite its portability, we do not believe we should write any more bash code because it has never, and will never, result in "library" code; it's been decades! This means everything you do with it is a dead-end. There is no momentum, and no standing on the shoulders of those that came before you. Over time, we hope to change that.
The docs are heavily under development as we transition from our old legacy tree based interpreter (sl-sh) to the register based virtual machine implementation of the language (slosh).
DOCS todos
wiki of under construction / todo docs
The Readme

Simple Lisp Shell (pronounced slosh)
Note this is a new experimental version, see ./legacy/ for the original version (slush).
Simple Lisp SHell (slosh) is a lisp based shell written in Rust. It is not POSIX compliant and makes no effort to be. Sl-sh should run on any *nix platform as well as macOS (CI currently only tests against ubuntu and macOS).It is a Lisp-1 that is heavily inspired by Clojure and Common Lisp. It is a shell, it is a scripting language, and it is a REPL.
Some of the more prominent features:
-
The terminal contains both a shell and a lisp reader so familiar bash-isms like
cat file | tr -s " " | cut -d " " -f 2,4
"just work", but starting a command with a lisp form (an s-expression) allows:
(dotimes 10 (prn "hello world"))
and the "boundary" can be easily crossed, the
$()
syntax calls out to the shell from within slosh code.(let ([pid, out] $(ls :>)) (iter::for l in (iter::iter out) (pr l)))
-
Support for an rc/init file,
~/.config/slosh/init.slosh
, to set up environment and fully customize your prompt. -
Common Lisp style macro system with support for quote and backquote (with clojure style ~ and ~@ expansion).
-
Dynamically Typed
-
Note lacks many features from legacy sl-sh but catching up (std lib is currently tiny).
Contains these crates:
- slosh: a REPL with debugger and extensions that use compiler, includes shell functionality.
- compiler: the core compiler code
- compile_state: helper crate with state contained by a VM for use with compiler
- vm: this is the bytecode VM that is target of the compiler
- builtins: set of some core builtins
- shell: contains shell specific code, this includes a shell reader (parser), job control etc
- bridge_macros: macros for exported Rust functions as slosh functions
- bridge_types: helper types for code using bridge_macros
- legacy (excluded): original sl-sh version, more complete but slower and worse core shell support
Running
cargo run -p slosh
Installation
1. Get sl-sh
- Install git
git clone https://github.com/sl-sh-dev/sl-sh cd slsh
2. Build sl-sh
- Install Rust and build from source:
cargo build -p slosh --release ./target/release/slosh
3. Use sl-sh as primary shell
- install binary
mkdir -p /usr/local/bin
sudo install -m 755 target/release/slosh /usr/local/bin/
- add slosh to /etc/shells and change login shell to slosh
echo /usr/local/bin/slosh | sudo tee -a /etc/shells
chsh -s /usr/local/bin/slosh
4. (Optional) Configure slosh
The slosh configuration file lives at ~/.config/slosh/init.slosh.
If you run slosh and the file does not exist, a default one will be created for you.
Review your existing shell configuration files like ~/.bashrc and ~/.bash_profile and manually translate them to slosh syntax and add to your init.slosh file
For example, export JAVA_HOME="/usr/local/opt/openjdk@11/bin/java"
becomes (sh "export JAVA_HOME='/usr/local/opt/openjdk@11/bin/java'")
Compiler
These are a subset of sl-sh forms and most work exactly the same. See the sl-sh docs at: https://sl-sh-dev.github.io/sl-sh/
Primitive types
- True
- False
- Nil
- String Constant
- Symbol
- Keyword
- Character (chars are grapheme clusters)
- Float (56 bit float)
- Integer (56 bit signed integer)
- Byte
Heap allocated objects (complex types)
- Pair/ConsCell
- Vector
- HashMap
- String
Special Forms
The following special forms are currently in the compiler:
- def
- set!
- do
- fn
- macro
- if
- quote (')
- back-quote (` supports ~ ~@)
- and
- or
- err
- let
- call/cc
- defer
- on-error
- while
Compiled Forms
Normal forms follow normal calling evaluation. Note: These are all compiled to bytecode and once compiled are not dynamic anymore.
- not
- recur
- this-fn
- type
-
-
- *
- /
- inc!
- dec!
- list
- list-append
- cons
- car
- cdr
- xar!
- xdr!
- vec
- make-vec
- vec-push!
- vec-pop!
- str
- =
- /=
- <
- <=
- >
- >=
- eq?
- equal?
Features
- Lisp reader (no reader macros yet)
- Lisp lists (pair/conscell based)
- Vectors
- Tail call optimization
- Continuations (call/cc)
- Lambda/Closures (supports optional and variadic arguments)
- Garbage collection (basic but should function)
- Lisp back quotes (including nested back quotes)
- Macros
slosh
Slosh is the shell and scripting language REPL using the compiler, vm and shell crates.
Built-in Forms
These forms (written in Rust but callable from Lisp) are supported.
- pr (print)
- prn (println)
- dasm (disassemble a lambda or closure)
- load (load a lisp file and execute it)
- vec-slice (new vec that is a slice of old vec)
- vec->list (turn a vec to a list)
- get-prop (get a property from an object- either a global variable or a heap object)
- set-prop (set a property on an object- either a global variable or a heap object)
- eval (eval an expression)
Features
- Line editor with history
- Debug on error, currently useful for probing VM state only
Links
- sl-sh legacy shell: https://github.com/sl-sh-dev/sl-sh/legacy
Benchmarking
- Install bencher
- To run benchmarks locally:
cargo bench
- To upload benchmarks to bencher.dev:
bencher run "cargo bench"
- Consider using iai in cloud: https://bencher.dev/learn/benchmarking/rust/iai/
Generated documentation
The documentation site is served from the doc
directory
based on the doc/mk-site.sh
script referenced in the github action .github/workflows/gh_pages.yml
.
Documentation can be built and viewed locally as the documentation site is a static set of html files generated from the source code.
All of this is covered in doc/README.md
Must be compiled in lisp-test mode for appropriate documentation functions to be present (cargo build --features lisp-test
).
Dev Notes
Development Tools
Just and the Justfile
Just is a command runner much like make, but with a simpler syntax.
Optionally, you can install Just and use it to help easily test or build slosh.
You can also read the Justfile in the root directory to see the common commands that we use to test and build the project.
To verify you've installed Just, run just
in the project root which should list all available commands.
Now you can run just test
instead of the verbose sh scripts/check-clippy-version.sh && cargo fmt && cargo clippy && cargo test --workspace
.
It's also possible to set up shell completion scripts which makes it quite quick to find the right command.
Using shell commands in lisp
Slosh can easily be used to launch processes in lisp mode (e.g. in a script). Interacting with the input and output of those programs can be done in a variety of ways.
Two main flavors of starting shell processes
- The $sh variety which is a little clunky as you directly pass it a string, as seen in the let binding.
- The $ reader macro which treats everything as a string but allows escaping slosh variables
directly in the shell with macro-like syntax
~
(defn parse-git-branch () (let (branch ($sh "git rev-parse --abbrev-ref HEAD 2>/dev/null"))
(if (= branch "")
(str "")
(do $(export BRANCH_NAME=~branch)
(str "(" branch ")")))))
~ under construction ~
instead of (sh "wc" "-l") we have $(wc -l) (def v "foo") $(echo ~foo) $(echo ~v)
calling shell commands in lisp code
3 ways
-
$() - reader-macro - convenient because it interprets everything as a string - can be used with macro like ~
-
(sh "") - regular function, but you have to pass it a string ** $() & (sh) are very similar.
-
($sh ) - like backticks, call to shell, and get back a slosh string, e.g. run this command and give me the output but we do not have a reader macro yet.
- this is not implemented w/ a reader macro but could be something like $(( )) except that might be ugly
- ($sh "git rev-parse --abbrev-ref HEAD 2>/dev/null")
- this returns a string, does more work for you
- (sh "git rev-parse --abbrev-ref HEAD 2>/dev/null")
- Returns the exit status if foreground and the PID if background. Add the '&' to the string to background it.
NOTE:
on the CLI typing $() directly on the REPL, but if you wrapped it in say a (do $()) it would work, REPL isn't smart enough yet to
pass the $() to the LISP repl
bash precedent
- diff <(echo "1\n2\n3") <(echo "echo 1\n\1\n3")
- https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html#Process-Substitution
Still figuring this out currently allows things like this (syntax will probably change):
Current iteration uses :< (same as :0<) to connect a file stdin and :> (same as :1>) to connect a file to stdout. These can also be used with file descriptors (for example :2> will connect a file to stderr). They can be mixed with other shell redirects and will just become part of the redirect stack. Each lisp redirect will return a file in a list (first element will be the PID of the final process).
Examples: (let ([pid, out] (sh "ls" :>)) (iter::for l in (iter::iter out) (pr l)))
(let ([pid, out, er] (sh "ls vm/src/ sdsdf" :> :2>))(prn "PID: " pid) (iter::for l in (iter::iter out)(pr "from out: " l))(iter::for l in (iter::iter er)(pr "from err: " l)
Set the lisp pipe then use a shell redirect to also send stderr to the same pipe: (let ([pid, out] (sh "ls vm/src/ sdsdf" :> "2>&1"))(prn "PID: " pid) (iter::for l in (iter::iter out)(pr "from grep: " l)))
(let ([pid, in, out] (sh :< "grep XX" :>))(prn "PID: " pid) (fprn in "XXsls")(fprn in "sls")(fprn in "dfdXX")(fclose in)(iter::for l in (iter::iter out)(pr "from grep: " l)))
(same as above but include a pipe between shell commands) (let ([pid, in, out] (sh :< "grep XX | cat -" :>)) (fprn in "XXsls")(fprn in "sls")(fprn in "dfdXX")(fclose in)(iter::for l in (iter::iter out)(pr l)))
slosh container/complex data types
TODO
- char/char literal
- bytes
- vec
- numbers / number literals
- boolean literals
String
A string. Strings in slosh are UTF8 encoded and are composed of chars that are UTF grapheme clusters. Because of the encoding strings can be indexed but they must be traversed to find an index (i.e. they are indexed by 'chars' not bytes).
Read only string constants can be created with double quotes in the Reader. For instance: (def str-const "Some String Const")
A mutable string can be created with the 'str' form, for instance: (def string (str "Some val: " val))
Characters at index can be accessed with dot notation (see Vector).
Other string functions:
- str: concats all the values provided (as strings) to produce a new string (mutable)
- str-replace
- str-trim
- str-trim!
- str-contains
- str-push!
- str-map
- str-empty?
- str-starts-with
- str-split
- char-whitespace?
Vector
A vector (dynamic array) of values. Typically a vector will be created with the '[' reader macro (expands to (vec ...)) for instance: (def vector[1 2 3]) Vectors can be indexed with 'dot' notation (dot is a reader macro that expends to a (get x index) for x.index. For example: (let (v [1 2 3]) (prn v.0 ", " v.1 ", " v.2)) Dot notation can also be used with set! to set elements: (let (v [1 2 3]) (set! v.0 10) (set! v.1 20) (set! v.2 30) (prn v.0 ", " v.1 ", " v.2))
Other vector functions:
- vec: longform for '[]' syntax, prefer using brackets
- make-vec: takes a capacity and default value, makes a vector of that size with all values set to default
- vec-push!: destructive, pushes a new value to the end of a vec (increases len by one)
- vec-pop!: destructive, pops the last value from a vector and returns it (decreases vector len by one)
- vec-slice: takes a vector, start index and optional end index (defaults to end of vector), returns a new vec of elements start (inclusive) end (exclusive)
HashMap
A map of key/value pairs. Use the '{' reader macro to create a hashmap: (def hm {:x 1, :y 2, :z 3}) Use dot notation (see vectors) to access and set keys: (let (hm {:x 1, :y 2, :z 3}) (set! hm.:x 10) (set! hm.:y 20) (set! hm.:z 30) (prn hm.:x ", " hm.:y ", " hm.:z))
Other hashmap function:
- make-hash: longform for '{}' reader macro, prefer '{}'
Pair/ConsCell/List
This is a traditional Lisp conscell data type, pair of values (car, cdr). It can be used to create a linked list of values.
Other Pair function:
- car
- cdr
- list
- list-append
- cons
- xar!
- xdr!
Common functions
These should all work on any of the containers.
- len: return the length of the container
- clear!: destructive form to remove all elements from the container
- set!: with dot notation to set an element of a container (see Vector and HashMap)
- dot notation: this is a reader macro the expends to (get val index) for val.index
Equality
The most common way to test equality is with =
For numeric equality (IEEE) use ==
For bytewise equality use identical?
The behavior and names are based on Clojure's implementation. Read their docs here: https://clojure.org/guides/equality
Also check out slosh/tests/equality.slosh
for some examples.
-
=
-
(= 2 0x2)
istrue
(comparing an int to a byte) -
(= 2 2.0)
isfalse
(comparing an int to a float) -
(= 0.0 -0.0)
istrue
-
(= NaN NaN)
isfalse
-
state.rs
defines special forms object with keyequal
mapped to the name=
. -
compile.rs
matches onenv.specials().equal
and generates opcodeEQUAL
-
exec_loop.rs
maps opcodeEQUAL
to functionis_equal
-
vm.rs
is_equal
converts each arg to aValue
(in case it needs to be dereferenced) and callsis_equal_pair
-
vm.rs
is_equal_pair
does a complex test for equality- check if both args are Byte or Int and if so, converts both to
i64
withValue::get_int
and compares with rust native==
- check if both args are numbers (Byte, Int, or Float) and if so, converts both to
f64
withValue::get_float
and compares with rust native==
- check if both args are Byte or Int and if so, converts both to
-
-
==
-
(== 1 1.0)
istrue
(comparing an int to a float) -
(== 0.0 -0.0)
istrue
-
(== NaN NaN)
isfalse
-
returns true whenever
=
does, but also returns true for numbers that are numerically equal -
when comparing two floats, converts two both to
f64
and compares with native f64==
-
does not use F56::PartialEq implementation
-
state.rs
defines special forms object with keynumeq
mapped to the name==
. -
compile.rs
callscompile_list
which callscompile_special
which callscompile_math
incompile_math.rs
-
compile_math.rs
compile_math
matches onenv.specials().numeq
and generates opcodeNUMEQ
-
exec_loop.rs
maps opcodeNUMEQ
to functioncompare_numeric
and passes a comparator|a,b| a == b
-
macros.rs
compare_numeric
- checks if either argument is a
Float
and if so, converts both tof64
withget_primitive_float
macro and uses the comparator - checks if either argument is a
Int
and if so, converts both toi64
withget_primitive_int
macro and uses the comparator
- checks if either argument is a
-
-
identical?
-
(identical? 1 1)
istrue
-
(identical? 1 1.0)
isfalse
(different types) -
(identical? 0.0 -0.0)
isfalse
(comparing floats with different bit patterns) -
(identical? NaN NaN)
might betrue
orfalse
. There are trillions of different bit patterns that represent NaN in IEEE 754 -
is the only equality comparison that uses
Value::PartialEq
implementation which is always false for different types of Values -
using identical equality for floats causes problems with hashing. #125 identical equality is 'too strict' in that you probably expect that +0 and -0 should hash to the same thing, but they don't rendering hash tables
-
state.rs
defines special forms object with keyeq
mapped to the nameidentical?
. -
compile.rs
matches onenv.specials().eq
and generates opcodeEQ
-
exec_loop.rs
maps opcodeEQ
to functionis_identical
-
vm.rs
is_identical
converts each arg to aValue
(in case it needs to be dereferenced) and comparesval1 == val2
which usesValue::PartialEq
implementation
-
-
assert-equal
- based on
=
- is a macro defined in core.slosh which checks if the arguments are
=
and throws an error if they are not
- based on
-
not=
- defined in
vm/core.slosh
as the negation of=
- defined in
-
not==
- defined in
vm/core.slosh
as the negation of==
- defined in
ERRORS
Error Type
The error type consists of an identifying keyword and a data/payload value. This value is typically a string but can be any valid value.
(type [error]) returns :Error The form (car [error]) returns the keyword identifying this error. The form (cdr [error]) returns the data value for the error. Note the use of car/cdr to pull apart an error even though it is not of the pair type. Use (mk-err :[ID] value) to create an error type or (err :[ID] value) to "raise" an error (see below).
Raising an error
Runtime errors will be "raised". This means the program execution will halt and the debugger will be entered. Currently this only allows examining the running state but will eventually include the ability to modify state and restart as other Lisps allow. Code can raise an error with the err form, for instance (err :some-error-type "This is my error") will raise an error and interrupt the program.
Note, the (get-error FORM+) form can be used to programmatically return a raised error instead of breaking to the debugger.
Returning an error
Code can return an error instead of breaking into the debugger. Use the (mk-err :[ERROR ID] vallue) to create an error and then use it as any other value (return it from a function for instance). This may be appropriate for a common error that does not warrent breaking to the debugger.
References
See the docs string for:
- err
- mk-err
- err?
- ok?
- get-error
Slosh/Lisp syntax and macros
The core unit of a Lisp is a form:
42
;; => 42
+
;; => #<SpecialFn(+)>
(list 1 2)
;; => (1 2)
;; The quote symbol means return the literal form after the character
;; This is identical to the form above.
'(1 2)
;; => (1 2)
are forms. All lisp code is structured as a sequence of forms inside forms separated by whitespace.
Expressions are enclosed in parentheses and Lisp uses prefix notation to parse expressions.
A parenthesized expression is a list of forms: (list 1 2 3 4)
where the first
form, the head, should generally be a function or a macro and dictates what the expression will do,
and the subsequent children are arguments to the head.
Comments
Single-line comments start with a ;
character and continue till the end of the line
; (prn "hello")
(prn "world")
;; => "world"
Multi-line comments start with the #|
characters to start and ends with the sample symbols reversed |#
.
#|
(prn "oh")
(prn "hello")
|#
(prn "world")
;; => "world"
Single forms can be commented out with #;
characters. This directive tells the reader to discard the form.
#;(prn "oh")
#;(prn "hello")
(prn "world")
;; => "world"
Documentation
Any symbol that is used with def
or defn
can also bind documentation. Documentation
is multiline and is delimited with #%
characters to start and ends with the same symbols reversed %#
.
#%
Usage: (login SECRET)
Returns true if logged in false if not. Must use `SECRET`
Section: secrets
Example:
(assert-false (login "foo"))
%#
(defn login (secret)
(if (= secret "helloworld")
#t
#f))
#%
Usage: (login SECRET)
Returns documentation for given symbol as map. Keyword is a documentation fragment
(usage, section, description, example) and value is text describing given fragment.
Section: secrets
Example:
(assert-false (login SECRET))
%#
(def SECRET "helloworld")
(prn (login SECRET))
;; => "true"
Macros
Helper macros syntax exists like in other lips such as:
quote ('
),
quasiquote (`
),
unquote (~
),
unquote-splice (~@
),
macro, and
defmacro.
(defmacro dotimes
;; This macro accepts times, some number, as well as some number of forms to be evaluated.
(times & body)
;; To avoid creating a variable name in the existing scope (gensym helps
;; with the creation of hygenic macros in slosh) is used and
;; the symbol i-name is assigned some random name.
(let (i-name (gensym))
;; The quasiquote is used within the body of the macro to specify that all forms
;; inside the parentheses should have an implicit quote in front of them. This
;; way, by default, the macro will return an ast with the literal forms, as opposed to the
;; evaulauted forms; forms can be evaluated in the resultant ast with the unquote.
`(let (~i-name 0)
;; i-iname and times are unquoted so they are evaluated ("escaping the
;; quasiquote") in the resultant ast returning numerical values instead
;; of symbols that evaluate to themselves.
(while (< ~i-name ~times)
;; Since body is a list, it utilizes the unquote-splice operator, to
;; expand each of its elements into the resultant ast, in the case
;; of dotimes `body` in intended to be some number of forms that
;; should be executed on each invocation.
~@body
;; because i-name is a symbol defined in the outer scope use unquote
;; so the resultant ast outputs `(inc! random-var-nmae)` rather than
;; (inc! i-name). `i-name` is not a symbol in scope in the resultant ast,
;; ~i-name evaluates to a symbol that is in scope in the resultant
;; ast.
(inc! ~i-name)))))
NOTE: The quasiquote is a quality of life macro helper, that obviates the need to add a single quote to every list and every form in the body of your macro. It is particularly useful in macros because often times many of the symbols you want returned in a macro are the literal symbols you want in the output ast.
Iterators
TODO PC/sls docs
this is the PR where iterators first went in to slosh inspiration for our iterators
Simple Lisp Debugger
:abort
- exit the debugger.
:globals
- prints all the globals
:dasm
- show the bytecode
:regs
- show stack that's available, e.g. the view of the stack your function has
:stack
- show call stack
:regs-raw
- TODO sls fix me
LET Bindings
Basic form
(let ([name value]) forms)
Let will create a new lexical scope and will bind names to local variables with provided values. After the binding it is an implicit do form. The bound symbols will only be in scope within this implicit do. Afterwards they will be unbound or will revert to their previous shadowed value.
Note all bindings are required to be pairs (name value), name is a symbol and value can be any form (it will be evaluated).
Let will shadow any variable names from outer scopes (including globals), it does not interact with dynamic scopes at all. Let is similar to let-rec in scheme, the bindings are created in order and later binding can see the values of previous bindings. It will also allow an early reference to "see" a later binding (like let-rec) allowing some recursive forms to be bound easily. Note that when doing this the later form must NOT be something being shadowed or the existing binding will be used not the new one in the let.
Examples
(let (a 1, b 2, c 3) `(~a ~b ~c))
;; => (1 2 3)
Produces (1 2 3)
(let (a 1, b 2, c 3) (let (b 20, c (+ b 10)) `(~a ~b ~c)))
;; => (1 20 30)
Produces (1 20 30)
(let (a 1, b 2, c 3) (let (x (+ b 1), b 20, c (+ b 10)) `(~a ~x ~b ~c)))
;; => (1 3 20 30)
Produces (1 3 20 30)
(let (fnx (fn (x) (if (= x 0) #t (fny (- x 1))))
fny (fn (y) (if (= y 0) #t (fnx (- y 1)))))
(fnx 10))
;; => true
Example of recursive references (a dumb one). It will produce #t (true) after ping ponging between fnx and fny.
(let (fny (fn (y) y))
(let (fnx (fn (x) (if (= x 0) #t (fny (- x 1))))
fny (fn (y) (if (= y 0) #t (fnx (- y 1)))))
(fny 10)))
;; => 8
This example will produce 8 because fnx will use the outer fny instead of the next fny.
Destructure bindings
Let supports destructure bindings of sequences (list, vector) and hashmaps. It can support optional bindings as well as rest (&) for sequences.
For sequences use [name+], if & is before the last name then it will get all the leftover values. A % indicates that all the names after are optional (default to nil) and you can use := to set the default value. Patterns must match exactly, for instance [a b c] requires a sequence with exactly three elements. [a b c & rest] requires a sequence with at least three elements. [% a b c & rest] will take any sequence and bind the first, second and third values to a b and c if available.
For maps use {[name key]+} (i.e. a map of symbols to keys), if this map contains :or then it's value will be a map of key to default value used for any missing keys. It requires all keys to be included in the destructured map or to have a default.
Note that destructures can be applied recursively and sequence destructure can contain map destructures and vice versa.
Examples
(def x '(1 2 3))
(let ([a b c] x) `(~a ~b ~c))
;; => (1 2 3)
Produces (1 2 3).
(let ([a b % c d] '(1 2)) (list a b c d))
;; => (1 2 nil nil)
Produces (1 2 nil nil).
(let ({a :one, b 'two, c "three" [d e] :vec} {:one 1, 'two 2, "three" 3, :vec [4 5]}) (list a b c d e))
;; => (1 2 3 4 5)
Produces (1 2 3 4 5).
Namespaces
Description
Namespaces are compiler bookkeeping for organizing global symbols. When in a namespace then any symbols that are defined will have the current NAMESPACE:: prepended to the symbol. When symbols are resolved the compiler will also try to prepend the current namespace first in order to find the symbol.
Entering a namespace
From code use the with-ns
form.
(doc 'with-ns)
;; => "Usage: (with-ns SYMBOL sexp+)
;;
;; Create a namespace and compile sexp+ within it. Restore the previous namespace when scope ends.
;; THe symbol "::" will return to the "root" namespace (i.e. no namespace prepended to globals).
;; This will cause all globals defined to have namespace:: prepended.
;; This will also clear any existing imports.
;;
;; Section: namespace
;;
;; Example:
;; (with-ns test-with-ns
;; (def ttf (fn () '(1 2 3)))
;; (test::assert-equal '(1 2 3) (ttf))
;; (test::assert-equal '(1 2 3) (test-out::ttf)))
;; (test::assert-equal '(1 2 3) (test-out::ttf))
;; "
From the top-level REPL you can use 'ns'.
(doc 'ns)
;; => "Usage: (ns SYMBOL)
;;
;; Changes to namespace. This is "open-ended" change and is intended for use with
;; the REPL prefer with-ns for scripts.
;; The symbol "::" will return to the "root" namespace (i.e. no namespace prepended to globals).
;; This will cause all globals defined to have namespace:: prepended.
;; This will also clear any existing imports.
;;
;; Section: namespace
;;
;; Example:
;; (ns testing)
;; (def x #t)
;; (test::assert-true x)
;; (ns ::)
;; (test::assert-true testing::x)
;; "
This is an open-ended namespace change intended for the repl, prefer with-ns for a scoped namespace in code.
Imports
Other namespaces can be imported to allow its symbols to be accessed in a shorter form. Use the 'import' form for this .
(doc 'import)
;; => "Usage: (import namespace [:as symbol])
;;
;; Will import a namespace. Without an :as then all symbols in the namespace will become available in the current
;; namespace as if local. With [:as symbol] then all namespace symbols become available with symbol:: prepended.
;;
;; Section: namespace
;;
;; Example:
;; (ns testing)
;; (def x #t)
;; (test::assert-true x)
;; (ns ::)
;; (test::assert-true testing::x)
;; (import testing)
;; (test::assert-true x)
;; (import testing :as t)
;; (test::assert-true t::x)
;; "
For instance using (import iter)
will allow any symbols in the iter namespace to be used without prepending 'iter::'. You can also use the (import iter :as i)
, the :as form allows the namespace to be given a different name. In this case the iter namespace could be replaced with 'i', (i::for ...) instead of (iter::for ...) for example. Imports are resolved in the order they are compiled in case of conflict (i.e. the first import that resolves a symbol wins). Imports are attached to the current namespace, changing namespaces will clear imports (note that 'with-ns' saves and restores the previous namespace with imports).
Loading code
To load new code into your environment use load or run-script.
Load
The load form should generally be preferred. It will compile the code at compile time (vs runtime) and execute it at runtime. This means:
- The path parameter has to be known at compile time: a string const, defined global or form that does not need local inputs.
- Any symbols defined in the loaded code will be known to the compiler at compile time and available for use.
(doc 'load)
;; => "Usage: (load path) -> [last form value]
;;
;; Read and eval a file (from path- a string). The load special form executes at compile time.
;; This means it's parameter must resolve at compile time. Most of the time you will want to use
;; this in conjunction with 'with-ns' to namespace the contents.
;; Note: on it's own does nothing with namespaces.
;;
;; Section: core
;;
;; Example:
;; (comp-time (def test-temp-file (get-temp-file)) nil)
;; (defer (fs-rm test-temp-file))
;; (let (tst-file (fopen test-temp-file :create))
;; (defer (fclose tst-file))
;; (fprn tst-file "(with-ns test-load")
;; (fprn tst-file " (defn test-fn () '(1 2 3)))"))
;; (load test-temp-file) ; put stuff in it's own namespace
;; (test::assert-equal '(1 2 3) (test-load::test-fn))
;;
;;
;; (with-ns test-out2
;; (comp-time
;; (def test-temp-file (get-temp-file))
;; (let (tst-file (fopen test-temp-file :create))
;; (defer (fclose tst-file))
;; (fprn tst-file "(defn test-fn () '(1 2 3))"))
;; nil)
;; (defer (fs-rm test-temp-file))
;; (load test-temp-file) ; put new stuff in current namespace
;; (test::assert-equal '(1 2 3) (test-fn))
;; (test::assert-equal '(1 2 3) (test-out2::test-fn)))
;; "
Run Script
The run-script form loads each form in the file, compiles and executes it at runtime. This means:
- It can take any parameter since it is resolved at runtime.
- Globals it defines will NOT be known until after it runs at runtime.
(doc 'run-script)
;; => "Usage: (run-script path) -> [last form value]
;;
;; Read and eval a file (from path- a string).
;;
;; Section: scripting
;;
;; Example:
;; (def test-load::test-fn)
;; (with-temp-file (fn (tmp)
;; (let (tst-file (fopen tmp :create))
;; (defer (fclose tst-file))
;; (fprn tst-file "(with-ns test-load")
;; (fprn tst-file " (defn test-fn () '(1 2 3)))"))
;; (run-script tmp)
;; (test::assert-equal '(1 2 3) (test-load::test-fn))))
;; "
End to End example of Slosh execution
- Start with the lisp program
(1.1)
- In
reader.rs
- The
read_inner
function controls most parsing.- Numeric parsing happens at the end in the catch-all of the match statement.
- The
do_atom
function attempts to parse 1.1 as an i64 and fails, so it parses it as f64 and then calls.into()
to convert to aValue
- In
main.rs
- The
exec_expression
function callspass1
- And then it calls
compile
- In
pass1.rs
- The
pass1
function initially operates on (1.1) as a pair or list - It iterates over each element of the list and recursively calls
pass1
on each element - So then
pass1
is called on 1.1 which is then handled in the catch-all of the match statement - and this is where we add 1.1 to the heap and add it is a constant to the vm
- In
state.rs
add_constant
is called which inserts theValue
of 1.1 intopub struct CompileState
'spub constants: HashMap<Value, usize>
- Since constants are stored in a hashmap, if two different numeric constants hash to the same thing, they will be stored as the same constant
- In
float_56.rs
F56
impl's theHash
trait and has a custom implementation ofhash
that converts theF56
to au64
and then hashes the result
- In
compile.rs
- Recall that
exec_expression
calledcompile
afterpass1
- calls to
compile
trickle down intocompile_list
,compile_special
,compile_math
, and others. compile_list
handles a single value like this and the match statement catch-all prints Boo and the value itself
FAQ
Does the syntax on the CLI differ from bash that much if at all?
No, not really.
Will sl-sh be supported on windows?
Work is being done in sl-liner and sl-console to make this possible but currently it is not supported.
Is it any good?
Yes
Slosh Forms
List of sections:
char, collection, conditional, conversion, core, doc, file, hashmap, io, iterator, math, namespace, pair, random, scripting, sequence, shell, string, system, test, type, vector
Section: char
char-lower, char-upper, char-whitespace?
Section: collection
clear!, empty?, flatten, in?, not-empty?, reverse
Section: conditional
<, <=, ==, >, >=, and, cond, if, match, not, or, when
Section: conversion
Section: core
=, apply, back-quote, block, comp-time, dec!, def, defmacro, defn, do, doc, doc-raw, dotimes, dotimes-i, dump-globals, dyn, err, eval, exit, expand-macro, fn, gensym, get-error, get-globals, get-prop, identity, inc!, is-noop, len, let, let-while, load, load-rc, loop, macro, mk-err, noop, noop-fn, not=, not==, nsubstitute!, occurs, on-raised-error, quote, recur, set!, set-prop, sizeof-heap-object, sizeof-value, substitute, to-list, to-vec, un-noop-fn, usage
Section: doc
build-doc, doc-map, get-exemptions, get-globals-sorted, legacy_forms
Section: file
cd, fclose, fflush, fopen, fs-accessed, fs-base, fs-crawl, fs-dir?, fs-exists?, fs-file?, fs-len, fs-modified, fs-parent, fs-rm, fs-same?, get-temp, get-temp-file, glob, read, read-all, read-line, temp-dir, with-temp, with-temp-file
Section: hashmap
hash-keys, hash-remove!, make-hash
Section: io
Section: iterator
iter::enumerate, iter::file-iter, iter::filter, iter::for, iter::iter, iter::iter-or-single, iter::iter?, iter::list-iter, iter::map, iter::mk-iter, iter::once-iter, iter::range, iter::reduce, iter::repeat-iter, iter::string-iter, iter::vec-iter, iter::vec-iter-pair, iter::vec-iter-rev, iter::enumerate, iter::file-iter, iter::filter, iter::for, iter::iter, iter::iter-or-single, iter::iter?, iter::list-iter, iter::map, iter::mk-iter, iter::once-iter, iter::range, iter::reduce, iter::repeat-iter, iter::string-iter, iter::vec-iter, iter::vec-iter-pair, iter::vec-iter-rev
Section: math
%, *, +, -, /, abs, rem, rem_euclid
Section: namespace
get-in-namespace, get-namespaces, import, ns, with-ns
Section: pair
Section: random
Section: scripting
Section: sequence
butlast, first, last, rest, seq-for
Section: shell
args, shell-exe, bg-color-rgb, fg-color-rgb, syntax-off, syntax-on, sys-command?
Section: string
str, str-bytes, str-cat-list, str-contains, str-empty?, str-lower, str-map, str-push!, str-replace, str-split, str-splitn, str-starts-with, str-sub, str-trim, str-trim!, str-upper
Section: system
Section: test
test::assert-equal, test::assert-error, test::assert-error-msg, test::assert-false, test::assert-not-equal, test::assert-true, test::assert-equal, test::assert-error, test::assert-error-msg, test::assert-false, test::assert-not-equal, test::assert-true
Section: type
->float, ->int, callable?, char?, err?, io?, list?, nil?, ok?, pair?, seq?, string?, symbol?, vec?
Section: vector
make-vec, vec, vec->list, vec-pop!, vec-push!, vec-slice
char
List of symbols:
char-lower, char-upper, char-whitespace?
char-lower
Usage: (char-lower char) -> char
Get lower case (utf) string for a character.
Example:
(test::assert-equal "a" (char-lower \A))
(test::assert-equal "a" (char-lower \a))
(test::assert-not-equal "a" (char-lower \Z))
(test::assert-equal "λ" (char-lower \Λ))
(test::assert-equal "λ" (char-lower \λ))
(test::assert-equal "ß" (char-lower \ß))
char-upper
Usage: (char-upper char) -> char
Get upper case (utf) string for a character.
Example:
(test::assert-equal "A" (char-upper \A))
(test::assert-equal "A" (char-upper \a))
(test::assert-not-equal "A" (char-upper \Z))
(test::assert-equal "Λ" (char-upper \λ))
(test::assert-equal "Λ" (char-upper \Λ))
;; "the" exception and a reason for returning a string
(test::assert-equal "SS" (char-upper \ß))
char-whitespace?
Usage: (char-whitespace? char) -> t/nil
Returns true if a character is whitespace, false/nil otherwise.
Example:
(test::assert-true (char-whitespace? \ ))
(test::assert-true (char-whitespace? \tab))
(test::assert-false (char-whitespace? \s))
collection
List of symbols:
clear!, empty?, flatten, in?, not-empty?, reverse
clear!
Usage: (clear! container)
Clears a container (vector, hash-map, string). This is destructive!
Example:
(def test-clear-vec (vec 1 2 3))
(test::assert-false (empty? test-clear-vec))
(clear! test-clear-vec)
(test::assert-true (empty? test-clear-vec))
empty?
Usage: (empty? v)
Usage (empty? s)
No Examples
flatten
Usage: (flatten & rest)
Takes a sequence composed of individual values or sequences of values and turns it into one vector of values.
Example:
(test::assert-equal [1 2 3 1 2 3] (flatten 1 2 3 (list 1 2 3)))
(test::assert-equal [1 2 3 1 2 3] (flatten 1 2 3 [1 2 3]))
(test::assert-equal [1 2 3 1 2] (flatten 1 2 3 (list 1 2)))
(test::assert-equal [1 2 3 1 2 3 1 2] (flatten 1 2 3 (list 1 2 3 (list 1 2))))
in?
Usage: (in? needle haystack)
In provided sequence, haystack, find a specific value, needle.
Example:
(test::assert-true (in? [1 2 3 4 5] 3))
(test::assert-false (in? [1 2 3 4 5] 9))
(test::assert-true (in? (list 1 2 3 4 5) 3))
(test::assert-true (in? '(1 2 3 4 5) 5))
not-empty?
Usage: (not-empty? v)
Usage (not-empty? s)
No Examples
reverse
Usage: (reverse items)
Produce a vector that is the reverse of items.
Example:
(let (tmap [1 2 3 0])
(test::assert-false (empty? tmap))
(set! tmap (reverse tmap))
(test::assert-equal 2 (get tmap 2))
(test::assert-equal 1 (get tmap 3))
(test::assert-equal 0 (get tmap 0))
(test::assert-error (reverse "string")))
conditional
For additional notes on conditionals involving equality see documentation site's equality section
List of symbols:
<, <=, ==, >, >=, and, cond, if, match, not, or, when
<
Usage: (< val0 ... valN)
Less than. Works for int, float or string.
Example:
(test::assert-true (< 1 2))
(test::assert-true (< 1 2 3 4))
(test::assert-false (< 2 2))
(test::assert-false (< 2 2 2))
(test::assert-false (< 2 2 3))
(test::assert-true (< 1.0 2.0))
(test::assert-false (< 2.0 2.0))
(test::assert-false (< 2.0 2.0 2.0))
(test::assert-false (< 2.0 2.0 3.0))
(test::assert-false (< 2.1 2.0 3.0))
(test::assert-false (< 2 1))
(test::assert-false (< 3 2 3))
(test::assert-true (< 1.0 1.1 ))
(test::assert-true (< 1.0 1.01 ))
(test::assert-true (< 1.0 1.001 ))
(test::assert-true (< 1.0 1.0001 ))
(test::assert-true (< 1.0 1.00001 ))
(test::assert-true (< 1.0 1.000001 ))
(test::assert-true (< 1.0 1.0000001 ))
(test::assert-false (< 1.0 1.00000000000001 ))
<=
Usage: (<= val0 ... valN)
Less than or equal. Works for int, float or string.
Example:
(test::assert-true (<= 1 2))
(test::assert-true (<= 2 2))
(test::assert-true (<= 2 2 2))
(test::assert-true (<= 2 2 3))
(test::assert-true (<= 1.0 2.0))
(test::assert-true (<= 2.0 2.0))
(test::assert-true (<= 2.0 2.0 2.0))
(test::assert-true (<= 2.0 2.0 3.0))
(test::assert-false (<= 2.1 2.0 3.0))
(test::assert-false (<= 2 1))
(test::assert-false (<= 3 2 3))
(test::assert-true (<= 1.00000000000001 1.0000000000001 ))
(test::assert-true (<= 10.0000000000001 10.000000000001))
(test::assert-true (<= 100.000000000001 100.00000000001))
(test::assert-true (<= 1000.000000000001 1000.00000000001))
==
Usage: (== val0 ... valN)
Equals. Works for numeric types (int, float).
Example:
(test::assert-false (== 1 2))
(test::assert-true (== 2 2))
(test::assert-true (== 2 2 2))
(test::assert-false (== 3 2 2))
(test::assert-false (== 3.0 2.0))
(test::assert-true (== 2.0 2.0))
(test::assert-true (== 2.0 2.0 2.0))
(test::assert-false (== 3.0 2.0 2.0))
(test::assert-false (== 2.1 2.0 3.0))
(test::assert-false (== 2 1))
(test::assert-false (== 3 2 1))
(test::assert-false (== 1.1 1.0))
(test::assert-true (== 1.1 1.1))
(test::assert-false (== 3 2 3))
>
Usage: (> val0 ... valN)
Greater than. Works for int, float or string.
Example:
(test::assert-false (> 1 2))
(test::assert-false (> 2 2))
(test::assert-false (> 2 2 2))
(test::assert-false (> 3 2 2))
(test::assert-true (> 3.0 2.0))
(test::assert-false (> 2.0 2.0))
(test::assert-false (> 2.0 2.0 2.0))
(test::assert-false (> 3.0 2.0 2.0))
(test::assert-false (> 2.1 2.0 3.0))
(test::assert-true (> 2 1))
(test::assert-true (> 3 2 1))
(test::assert-true (> 1.1 1.0))
(test::assert-false (> 3 2 3))
(test::assert-true (> 1.001 1.0))
(test::assert-true (> 1.0000001 1.0))
(test::assert-false (> 1.00000000000001 1.0))
>=
Usage: (>= val0 ... valN)
Greater than or equal. Works for int, float or string.
Example:
(test::assert-false (>= 1 2))
(test::assert-true (>= 2 2))
(test::assert-true (>= 2 2 2))
(test::assert-true (>= 3 2 2))
(test::assert-true (>= 3.0 2.0))
(test::assert-true (>= 2.0 2.0))
(test::assert-true (>= 2.0 2.0 2.0))
(test::assert-true (>= 3.0 2.0 2.0))
(test::assert-false (>= 2.1 2.0 3.0))
(test::assert-true (>= 2 1))
(test::assert-true (>= 1.1 1.0))
(test::assert-false (>= 3 2 3))
(test::assert-true (>= 1.0000000000001 1.00000000000001))
(test::assert-true (>= 10.000000000001 10.0000000000001))
(test::assert-true (>= 100.00000000001 100.000000000001))
(test::assert-true (>= 1000.00000000001 1000.000000000001))
and
Usage: (and exp0 ... expN) -> [false(#f) or expN result]
Evaluates each form until one produces nil or false(#f), produces false(#f) if any form is nil/#f or the result of the last expression.
The and form will stop evaluating when the first expression produces nil/#f.
Example:
(test::assert-equal #f (and nil (err "and- can not happen")))
(test::assert-equal #f (and #f (err "and- can not happen")))
(test::assert-equal "and- done" (and #t "and- done"))
(test::assert-equal "and- done" (and #t #t "and- done"))
(test::assert-equal 6 (and #t #t (+ 1 2 3)))
(test::assert-equal 6 (and (/ 10 5) (* 5 2) (+ 1 2 3)))
cond
Usage: (cond ((test form*)*) -> result
Evaluate each test in order. If it is true then evaluate the form(s) in an implicit do and return the result. Stop evaluating at the first true test. Return nil if no conditions are true.
Example:
(def b 0)
(defn select-option (a)
(cond ((= a 1) "opt-one")
((= a 2) (set! b 5) "opt-two")
((= a 3) (str "opt" "-three"))))
(defn select-option-def (a)
(cond ((= a 1) "opt-one")
((= a 2) "opt-two")
((= a 3) (str "opt" "-three"))
(#t "default")))
(test::assert-equal "opt-one" (select-option 1))
(test::assert-equal b 0)
(test::assert-equal "opt-two" (select-option 2))
(test::assert-equal b 5)
(test::assert-equal "opt-three" (select-option 3))
(test::assert-equal nil (select-option 4))
(test::assert-equal "opt-one" (select-option-def 1))
(test::assert-equal "opt-two" (select-option-def 2))
(test::assert-equal "opt-three" (select-option-def 3))
(test::assert-equal "default" (select-option-def 4))
if
Usage: (if p1 a1 p2 a2 ... pn an?) -> [evaled form result]
If conditional. Will evaluate p1 and if true (i.e. not nil or false) then return the evaluation of a1, if falsey(i.e. nil or false) evaluate p2 and so on. On an odd number of arguments (an is missing) then evaluate and return pn. Return false(#f) if no predicate is true. This degenerates into the traditional (if predicate then-form else-form). NOTE: Both nil and false(#f) are 'falsey' for the purposes of if.
Example:
(def test-if-one
(if #t "ONE TRUE" "ONE FALSE"))
(def test-if-two
(if nil "TWO TRUE" "TWO FALSE"))
(def test-if-three
(if #f "THREE TRUE" "THREE FALSE"))
(test::assert-equal "ONE TRUE" test-if-one)
(test::assert-equal "TWO FALSE" test-if-two)
(test::assert-equal "THREE FALSE" test-if-three)
(def test-if-one2
(if #t "ONE2 TRUE"))
(def test-if-two2
(if nil "TWO2 TRUE"))
(def test-if-three2
(if #f "THREE2 TRUE"))
(test::assert-equal "ONE2 TRUE" test-if-one2)
(test::assert-equal #f test-if-two2)
(test::assert-equal #f test-if-three2)
(def test-if-one2
(if nil "ONE FALSE" #t "ONE TRUE" #t "ONE TRUE2"))
(def test-if-two2
(if nil "TWO TRUE" #f "TWO FALSE" #t "TWO TRUE2"))
(def test-if-three2
(if #f "THREE TRUE" nil "THREE FALSE" "THREE DEFAULT"))
(test::assert-equal "ONE TRUE" test-if-one2)
(test::assert-equal "TWO TRUE2" test-if-two2)
(test::assert-equal "THREE DEFAULT" test-if-three2)
(test::assert-equal nil (if nil))
(test::assert-equal #f (if nil #t nil #t nil #t))
match
Usage: (match condition (value form*)*) -> result
Evaluate condition and look for matching value in each branch of type (value form*). Form(s) will be wrapped in an implicit do. Use nil to take action if no match (encouraged!).
Example:
(defn select-option (a)
(match a (1 "opt-one")
(2 (set! b 5) "opt-two")
(3 (str "opt" "-three"))))
(defn select-option-def (a)
(match a (1 "opt-one")
(2 "opt-two")
(3 (str "opt" "-three"))
(nil "default")))
(def b 0)
(test::assert-equal b 0)
(test::assert-equal "opt-one" (select-option 1))
(test::assert-equal "opt-two" (select-option 2))
(test::assert-equal b 5)
(test::assert-equal "opt-three" (select-option 3))
(test::assert-equal #f (select-option 4))
(test::assert-equal "opt-one" (select-option-def 1))
(test::assert-equal "opt-two" (select-option-def 2))
(test::assert-equal "opt-three" (select-option-def 3))
(test::assert-equal "default" (select-option-def 4))
not
Usage: (not expression)
Return true(#t) if expression is nil, false(#f) otherwise.
Example:
(test::assert-true (not nil))
(test::assert-false (not 10))
(test::assert-false (not #t))
(test::assert-false (not (+ 1 2 3)))
or
Usage: (or exp0 ... expN) -> [false(#f) or first non nil expression]
Evaluates each form until one produces a non-nil/non-false result, produces #f if all expressions are 'falsey'.
The or form will stop evaluating when the first expression produces non-nil/false.
Example:
(test::assert-true (or nil nil #t (err "and- can not happen")))
(test::assert-true (or #f nil #t (err "and- can not happen")))
(test::assert-true (or #f #f #t (err "and- can not happen")))
(test::assert-equal #f (or nil nil nil))
(test::assert-equal #f (or #f nil nil))
(test::assert-equal #f (or #f nil #f))
(test::assert-equal #f (or #f #f #f))
(test::assert-equal "or- done" (or nil "or- done"))
(test::assert-equal "or- done" (or nil nil "or- done"))
(test::assert-equal 6 (or nil nil (+ 1 2 3)))
(test::assert-equal 2 (or (/ 10 5) (* 5 2) (+ 1 2 3)))
when
Usage: (when provided-condition if-true)
when is a convenience function used to check a form, provided-condition, and run some form, if-true, if provided-condition evaluates to true.
Example:
(test::assert-true (when #t #t))
(test::assert-false (when #t nil))
(test::assert-false (when nil nil))
conversion
List of symbols:
->key
Usage: (->key exp) -> keyword
Converts exp to a keyword.
No Examples
->sym
Usage: (->sym exp) -> symbol
Converts exp to a symbol.
No Examples
def?
Usage: (def? symbol) -> #t/#f
If symbol is defined then return true else false.
No Examples
ref
Usage: (ref symbol) -> Value
If symbol is defined then return the thing it references.
No Examples
core
List of symbols:
=, apply, back-quote, block, comp-time, dec!, def, defmacro, defn, do, doc, doc-raw, dotimes, dotimes-i, dump-globals, dyn, err, eval, exit, expand-macro, fn, gensym, get-error, get-globals, get-prop, identity, inc!, is-noop, len, let, let-while, load, load-rc, loop, macro, mk-err, noop, noop-fn, not=, not==, nsubstitute!, occurs, on-raised-error, quote, recur, set!, set-prop, sizeof-heap-object, sizeof-value, substitute, to-list, to-vec, un-noop-fn, usage
=
Usage: (= val0 val1)
Test equality, works for most value types where it makes sense, not just primitives.
Example:
(test::assert-false (= "aab" "aaa"))
(test::assert-true (= "aaa" "aaa"))
(test::assert-true (= "aaa" "aaa" "aaa"))
(test::assert-false (= "aaa" "aaaa" "aaa"))
(test::assert-false (= "ccc" "aab" "aaa"))
(test::assert-false (= "aaa" "aab"))
(test::assert-true (= (get-error (/ 1 0)) (get-error (/ 1 0))))
apply
Usage: (apply function arg* list)
Call the provided function with the supplied arguments, if last is a list or vector then it will be "spread" as arguments. For instance (apply pr 1 2 3 [4 5 6]) is equivalent to (pr 1 2 3 4 5 6).
Example:
(def test-apply-one (apply str "O" "NE"))
(test::assert-equal "ONE" test-apply-one)
(test::assert-equal 10 (apply + 1 2 7))
(test::assert-equal 10 (apply + 1 [2 7]))
(test::assert-equal 10 (apply + 1 '(2 7)))
(test::assert-equal 10 (apply + [1 2 7]))
(test::assert-equal 10 (apply + '(1 2 7)))
(def test-apply-fn1 (fn (& args) (apply + args)))
(test::assert-equal 10 (apply test-apply-fn1 1 2 7))
(test::assert-equal 10 (apply test-apply-fn1 1 [2 7]))
(test::assert-equal 10 (apply test-apply-fn1 1 '(2 7)))
(test::assert-equal 10 (apply test-apply-fn1 [1 2 7]))
(test::assert-equal 10 (apply test-apply-fn1 '(1 2 7)))
(def test-apply-fn2 (fn (x y z) (+ x y z)))
(test::assert-equal 10 (apply test-apply-fn2 1 2 7))
(test::assert-equal 10 (apply test-apply-fn2 1 [2 7]))
(test::assert-equal 10 (apply test-apply-fn2 1 '(2 7)))
(test::assert-equal 10 (apply test-apply-fn2 [1 2 7]))
(test::assert-equal 10 (apply test-apply-fn2 '(1 2 7)))
back-quote
Usage: `expression -> expression
Return expression without evaluation. Always use the ` reader macro or expansion will not work (i.e. (back-quote expression) will not do , expansion).
Backquote (unlike quote) allows for symbol/form evaluation using , or ,@.
Example:
(test::assert-equal (list 1 2 3) `(1 2 3))
(test::assert-equal `(1 2 3) '(1 2 3))
(def test-bquote-one 1)
(def test-bquote-list '(1 2 3))
(test::assert-equal (list 1 2 3) `(~test-bquote-one 2 3))
(test::assert-equal (list 1 2 3) `(~@test-bquote-list))
block
Usage: (get-error exp0 ... expN) -> pair
Evaluate each form (like do) but on error return (:error msg backtrace) instead of aborting. On success return (:ok . expN-result).
If there is no error will return the value of the last expression as the cdr of the pair. Always returns a pair with the first value either being :ok or :error.
Example:
(let (get-error-t1 (get-error (err (mk-err :string (str "Some Error")))))
(test::assert-equal :error (car get-error-t1))
(test::assert-equal "error [string]: \"Some Error\"" (str (cdr get-error-t1))))
(test::assert-equal "Some String" (get-error "Some String"))
(test::assert-equal "Some Other String" (get-error (let (test-get-error "Some ") (str test-get-error "Other String"))))
comp-time
Usage: (comp-time sexp+)
Compile and execute sexp+ at compile time. The result of the final sexp will then be compiled into the current module being compiled (produce nil to avoid this).
Example:
(with-ns test-out
(comp-time '(def ttf (fn () '(1 2 3))))
(comp-time (def ttf2 (fn () '(1 2 3))) nil)
(test::assert-equal '(1 2 3) (ttf))
(test::assert-equal '(1 2 3) (test-out::ttf))
(test::assert-equal '(1 2 3) (ttf2))
(test::assert-equal '(1 2 3) (test-out::ttf2)))
dec!
Usage: (dec! symbol [number]) -> new value
Decrement the value in symbol by one or the optional number
Example:
(def *dec-test* 5)
(test::assert-equal 4 (dec! *dec-test*))
(test::assert-equal 4 *dec-test*)
(test::assert-equal 1 (dec! *dec-test* 3))
(test::assert-equal 1 *dec-test*)
(let (dec-test 5)
(test::assert-equal 4 (dec! dec-test))
(test::assert-equal 4 dec-test)
(test::assert-equal 1 (dec! dec-test 3))
(test::assert-equal 1 dec-test))
def
Usage: (def symbol doc_string? expression) -> expression
Adds an expression to the current namespace. Return the expression that was defined. Symbol is not evaluated. Can take an option doc string (docstrings can only be set on namespaced (global) symbols).
Example:
(def test-do-one nil)
(def test-do-two nil)
(def test-do-three (do (set! test-do-one "One")(set! test-do-two "Two")"Three"))
(test::assert-equal "One" test-do-one)
(test::assert-equal "Two" test-do-two)
(test::assert-equal "Three" test-do-three)
(let (test-do-one nil)
; Add this to the let's scope (shadow the outer test-do-two).
(test::assert-equal "Default" (def test-do-four "Default"))
; set the currently scoped value.
(set! test-do-one "1111")
(set! test-do-two "2222")
(test::assert-equal "1111" test-do-one)
(test::assert-equal "2222" test-do-two)
(test::assert-equal "Default" test-do-four))
; Original outer scope not changed.
(test::assert-equal "One" test-do-one)
(test::assert-equal "Default" test-do-four)
defmacro
Usage: (defmacro name argument_list body)
Create a macro and bind it to a symbol in the current scope.
Example:
(defmacro test-mac (x) `(inc! ~x))
(def test-mac-x 2)
(test-mac test-mac-x)
(test::assert-equal 3 test-mac-x)
(defmacro test-mac (x) `(set! ~x 15))
(test-mac test-mac-x)
(test::assert-equal 15 test-mac-x)
defn
Usage: (defn name args body)
Define a named function in the current namespace.
Example:
(defn defn-test (x y) (+ x y))
(test::assert-equal 5 (defn-test 2 3))
(defn defn-test (x y) (set! x (* x 2)) (+ x y))
(test::assert-equal 7 (defn-test 2 3))
(defn defn-test (x y) nil)
(test::assert-false (defn-test 2 3))
(defn defn-test (x y) #t)
(test::assert-true (defn-test 2 3))
do
Usage: (do exp0 ... expN) -> expN
Evaluate each form and return the last.
Example:
(def test-do-one nil)
(def test-do-two nil)
(def test-do-three (do (set! test-do-one "One") (set! test-do-two "Two") "Three"))
(test::assert-equal "One" test-do-one)
(test::assert-equal "Two" test-do-two)
(test::assert-equal "Three" test-do-three)
doc
Usage: (doc sym)
Print the documentation for provided symbol.
No Examples
doc-raw
Usage: (doc-raw sym [SCRATCH] [SCRATCH] docs has-usage)
Return the documentation for provided symbol as a string.
No Examples
dotimes
Usage: (dotimes times body [SCRATCH] [SCRATCH] i-name)
Evaluate body a number of times equal to times' numerical value.
Example:
(def i 0)
(dotimes 11 (set! i (+ 1 i)))
(test::assert-equal 11 i)
dotimes-i
Usage: (dotimes-i idx-bind times body)
Evaluate body a number of times equal to times' numerical value. Includes an incrementing reference binding, idx-bind, accessible in body.
Example:
(def i 0)
(def i-tot 0)
(dotimes-i idx 11 (do (set! i-tot (+ idx i-tot))(set! i (+ 1 i))))
(test::assert-equal 11 i)
(test::assert-equal 55 i-tot)
dump-globals
Usage: (dump-globals)
Prints the global variables to stdout.
Example:
#t
dyn
Usage: (dyn key value expression) -> result_of_expression
Creates a dynamic binding for key, assigns value to it and evals expression under it. Note that if key must be a symbol and is not evaluated.
The binding is gone once the dyn form ends. This is basically a set! on the binding in an unwind protect to reset it when done. When used on a global will set the first binding found and reset it when done. Calls to dyn can be nested and previous dynamic values will be restored as interior dyn's exit.
Example:
(def *dyn-test* 1)
(defn test-dyn-fn (val) (str *dyn-test* val))
(def out (dyn *dyn-test* 11 (test-dyn-fn 101)))
(test::assert-equal "11101" (str out))
;; when file handling works
;;(defn test-dyn-fn () (prn "Print dyn out"))
;;(dyn *stdout* (open "/tmp/sl-sh.dyn.test" :create :truncate) (test-dyn-fn))
;;(test::assert-equal "Print dyn out" (read-line (open "/tmp/sl-sh.dyn.test" :read)))
err
Usage: (err :keyword value)
Raises an error with keyword and value. By default this will break into the debugger like a runtime error (use get-error to avoid this).
Example:
(let (error (get-error (err :test "Test error")))
(test::assert-equal :test (car error))
(test::assert-equal "Test error" (cdr error))
(test::assert-true (err? error)))
eval
Usage: (eval expression)
Evaluate the provided expression. If expression is a list it will be compiled and executed and the result returned other values will just be returned (i.e. (eval 1) = 1, (eval "test") = "test", (eval [1 2 3]) = [1 2 3], etc).
Note eval is a function not a special form, the provided expression will be evaluated as part of a call.
Example:
(test::assert-equal "ONE" (eval "ONE"))
(test::assert-equal 10 (eval 10))
(test::assert-equal [1 2 3] (eval [1 2 3]))
(test::assert-equal 10 (eval '(+ 1 2 7)))
(test::assert-equal 10 (eval '(apply + 1 2 7)))
(test::assert-equal 10 (eval '(apply + 1 '(2 7))))
(test::assert-equal 10 (eval '(apply + '(1 2 7))))
(test::assert-equal 10 (eval '(apply + 1 [2 7])))
(test::assert-equal 10 (eval '(apply + [1 2 7])))
exit
Usage: (exit int)
Exit shell with provided exit code.
Example:
#t
expand-macro
Usage: (expand-macro 'code)
Output code, any macro invocation will be replaced with the code it would generate. This is particularly useful for introspection when debugging macros.
Example:
#t
fn
Usage: (fn (param*) expr*) -> exprN
Create a function (lambda).
Example:
(def test-fn1 nil)
(def test-fn2 nil)
(def test-fn3 nil)
(def test-fn-empty ((fn () nil)))
(test::assert-false test-fn-empty)
((fn () (set! test-fn1 1)))
(test::assert-equal 1 test-fn1)
((fn () (set! test-fn1 10)(set! test-fn2 2)))
(test::assert-equal 10 test-fn1)
(test::assert-equal 2 test-fn2)
((fn () (set! test-fn1 11)(set! test-fn2 20)(set! test-fn3 3)))
(test::assert-equal 11 test-fn1)
(test::assert-equal 20 test-fn2)
(test::assert-equal 3 test-fn3)
((fn (x y z) (set! test-fn1 x)(set! test-fn2 y)(set! test-fn3 z)) 12 21 30)
(test::assert-equal 12 test-fn1)
(test::assert-equal 21 test-fn2)
(test::assert-equal 30 test-fn3)
(test::assert-equal 63 ((fn (x y z) (set! test-fn1 x)(set! test-fn2 y)(set! test-fn3 z)(+ x y z)) 12 21 30))
gensym
Usage: (gensym)
Used to make macros hygenic by creating a random symbol name to be used in code output by a macro to avoid conflicting variable names.
Example:
#t
get-error
Usage: (get-error exp0 ... expN) -> pair
Evaluate each form (like do) but on error return (:error msg backtrace) instead of aborting. On success return (:ok . expN-result).
If there is no error will return the value of the last expression as the cdr of the pair. Always returns a pair with the first value either being :ok or :error.
Example:
(let (get-error-t1 (get-error (err (mk-err :string (str "Some Error")))))
(test::assert-equal :error (car get-error-t1))
(test::assert-equal "error [string]: \"Some Error\"" (str (cdr get-error-t1))))
(test::assert-equal "Some String" (get-error "Some String"))
(test::assert-equal "Some Other String" (get-error (let (test-get-error "Some ") (str test-get-error "Other String"))))
get-globals
Usage: (get-globals)
Return a vector containing all the symbols currently defined globally.
No Examples
get-prop
Usage: (get-prop 'a-symbol :a-property))
Read property that maps to given keyword for provided-symbol. Most forms have a :doc-string property that returns the docstring for the symbol.
Example:
#t
identity
Usage: (identity arg)
Identity function.
Example:
(test::assert-equal 0 (identity 0))
inc!
Usage: (inc! symbol [number]) -> new value
Increment the value in symbol by one or the optional number
Example:
(def *inc-test* 1)
(test::assert-equal 2 (inc! *inc-test*))
(test::assert-equal 2 *inc-test*)
(test::assert-equal 5 (inc! *inc-test* 3))
(test::assert-equal 5 *inc-test*)
(let (inc-test 1)
(test::assert-equal 2 (inc! inc-test))
(test::assert-equal 2 inc-test)
(test::assert-equal 5 (inc! inc-test 3))
(test::assert-equal 5 inc-test))
is-noop
Usage: (is-noop 'fn-to-test)
Report whether or not the provided function is currently set to do nothing. When called with the 'noop function always returns true.
Example:
(test::assert-true (is-noop 'noop))
(test::assert-false (is-noop 'fs-meta))
len
Usage: (len expression) -> int
Return length of supplied expression. The length of an atom is 1.
Example:
(test::assert-equal 0 (len nil))
(test::assert-equal 5 (len "12345"))
; Note the unicode symbol is only one char even though it is more then one byte.
(test::assert-equal 6 (len "12345Σ"))
(test::assert-equal 3 (len '(1 2 3)))
(test::assert-equal 3 (len [1 2 3]))
(test::assert-equal 3 (len (list 1 2 3)))
(test::assert-equal 3 (len (vec 1 2 3)))
(test::assert-equal 1 (len 100))
(test::assert-equal 1 (len 100.0))
(test::assert-equal 1 (len \tab))
let
Usage: (let vals &rest let-body)
Takes list, vals, of form ((binding0 sexp0) (binding1 sexp1) ...) and evaluates let-body with all values of binding bound to the result of the evaluation of sexp.
Example:
(def test-do-one "One1")
(def test-do-two "Two1")
(def test-do-three (let (test-do-one "One") (set! test-do-two "Two")(test::assert-equal "One" test-do-one)"Three"))
(test::assert-equal "One1" test-do-one)
(test::assert-equal "Two" test-do-two)
(test::assert-equal "Three" test-do-three)
((fn (idx) (let (v2 (+ idx 2) v3 (+ idx 3))
(test::assert-equal (+ idx 2) v2)
(test::assert-equal (+ idx 3) v3)
(if (< idx 5) (recur (+ idx 1)))))0)
((fn (idx) (let (v2 (+ idx 2) v3 (+ idx 3))
(test::assert-equal (+ idx 2) v2)
(test::assert-equal (+ idx 3) v3)
(if (< idx 5) (this-fn (+ idx 1)))))0)
let-while
Usage: (let-while (initial-bindings) (loop bindings) condition & let-body)
Takes list of initial bindings (done once before loop) of form (binding0 sexp0, binding1 sexp1, ...), and a list of loop bindings (done at the start of each iteration including the first) and evaluates let-body with all values of binding bound to the result of the evaluation of both bindings while condition is true.
Example:
; both of these examples create a vector and iterate to print all the elements
; use traditional lisp structure
(def test-res [])
(let-while (l [1 2 3]) (done (empty? l), f (first l), l (rest l)) (not done)
(prn f)
(vec-push! test-res f))
(let ([x y z] test-res)
(test::assert-equal 1 x)
(test::assert-equal 2 y)
(test::assert-equal 3 z))
; same thing using destructuring
(def test-res [])
(let-while (l [1 2 3]) (done (empty? l), [% f & l] l) (not done)
(prn f)
(vec-push! test-res f))
(let ([x y z] test-res)
(test::assert-equal 1 x)
(test::assert-equal 2 y)
(test::assert-equal 3 z))
load
Usage: (load path) -> [last form value]
Read and eval a file (from path- a string). The load special form executes at compile time. This means it's parameter must resolve at compile time. Most of the time you will want to use this in conjunction with 'with-ns' to namespace the contents. Note: on it's own does nothing with namespaces.
Example:
(comp-time (def test-temp-file (get-temp-file)) nil)
(defer (fs-rm test-temp-file))
(let (tst-file (fopen test-temp-file :create))
(defer (fclose tst-file))
(fprn tst-file "(with-ns test-load")
(fprn tst-file " (defn test-fn () '(1 2 3)))"))
(load test-temp-file) ; put stuff in it's own namespace
(test::assert-equal '(1 2 3) (test-load::test-fn))
(with-ns test-out2
(comp-time
(def test-temp-file (get-temp-file))
(let (tst-file (fopen test-temp-file :create))
(defer (fclose tst-file))
(fprn tst-file "(defn test-fn () '(1 2 3))"))
nil)
(defer (fs-rm test-temp-file))
(load test-temp-file) ; put new stuff in current namespace
(test::assert-equal '(1 2 3) (test-fn))
(test::assert-equal '(1 2 3) (test-out2::test-fn)))
load-rc
Usage: (load-rc) | (load-rc "init.slosh)
Read and eval user's rc file, by default "init.slosh" or a user provided file path found in '$HOME/.config/slosh/'.
No Examples
loop
Usage: (loop params bindings body)
Binds bindings to parameters in body. Use recur with desired bindings for subsequent iteration. Within the loop the lambda 'break' will end the loop, break can take an option argument that is what the loop produces (nil if no argument).
Example:
(def tot 0)
(loop (idx) (3) (do
(set! tot (+ tot 1))
(if (> idx 1) (recur (- idx 1)))))
(test::assert-equal 3 tot)
(def tot 0)
(loop (idx) (0)
(set! tot (+ tot 1))
(when (not (= idx 2))
(recur (+ idx 1))))
(test::assert-equal 3 tot)
(test::assert-equal 11 (loop (idx) (0)
(if (= idx 2) (break 11))
(recur (+ idx 1))))
(test::assert-false (loop (idx) (0)
(if (= idx 2) (break nil))
(recur (+ idx 1))))
(test::assert-error (loop (idx) (0)
(if (= idx 2) (break 1 3))
(recur (+ idx 1))))
macro
Usage: (macro (args) `(apply + ,@args))
Define an anonymous macro.
Example:
(def test-macro1 nil)
(def test-macro2 nil)
(def test-macro-empty (macro () nil))
(test::assert-false (test-macro-empty))
(def test-mac nil)
(def mac-var 2)
(let (mac-var 3)
(set! test-mac (macro (x) (set! test-macro2 100) (test::assert-equal 3 mac-var) (* mac-var x))))
(set! test-macro1 (test-mac 10))
(test::assert-equal 30 test-macro1)
(test::assert-equal 100 test-macro2)
mk-err
Usage: (mk-err :keyword value)
Create an error object. This does not raise the error but merely creates it. Can use car/cdr to extract the keyword and value.
Example:
(let (error (mk-err :test "Test error"))
(test::assert-equal :test (car error))
(test::assert-equal "Test error" (cdr error))
(test::assert-true (err? error)))
noop
Usage: (noop any*)
Takes any number of arguments and always returns nil.
Example:
(test::assert-equal nil (noop 'noop))
(test::assert-equal nil (noop "foo" :bar 'baz))
(test::assert-equal nil (noop))
noop-fn
Usage: (noop-fn 'fn-to-noop)
Alter the runtime so that the provided function is a no-operation (no-op or noop) that does nothing and returns nil for the provided function. Any future call to this function will do nothing, regardless of the arguments it is given.
Example:
#t
not=
Usage: (not= arg1 arg2)
Test if two values are not equal using =
Example:
(test::assert-true (not= 0 1))
(test::assert-true (not= 1 1.0))
(test::assert-false (not= 2 2))
(test::assert-false (not= 0.0 -0.0))
not==
Usage: (not== arg1 arg2)
Test if two values are not numerically equal using ==
Example:
(test::assert-true (not== 0 1))
(test::assert-false (not== 1 1.0))
(test::assert-false (not== 0.0 -0.0))
(test::assert-false (not== 2 2))
nsubstitute!
Usage: (nsubstitute! lst old-item new-item mods [SCRATCH] [SCRATCH] early-return)
Replaces all instances of old-item in lst with new-item. If last argument passed in is keyword :first only the first instance of old-item will be replaced.
Example:
(let (lst (list 1 2 3 4 5))
(test::assert-equal (list 1 2 2 4 5) (nsubstitute! lst 3 2))
(test::assert-equal (list 1 2 2 4 5) lst)
(test::assert-equal (list 1 3 2 4 5) (nsubstitute! lst 2 3 :first)))
occurs
Usage: (occurs (list 1 2 ...) 7)
Counts instances of item in sequence.
Example:
(test::assert-equal 1 (occurs (list 1 3 5 2 4 8 2 4 88 2 1) 8))
(test::assert-equal 3 (occurs (list 1 3 5 2 4 10 2 4 88 2 1) 2))
(test::assert-equal 0 (occurs (list 1 3 5 2 4 10 2 4 88 2 1) 42))
on-raised-error
Usage: (on-raised-error (fn (error) ...))
Low level (consider this unstable) interface to the raised error machinery. Useful for building higher level error handling (get-error for instance). It takes either Nil or a callable with one parameter. That parameter will be the error that was raised. The entire running "chunk" of code will be displaced for the installed handler. Probably best to use this with a continuation or a function that ends in a continuation call otherwise it may be difficult to reason about...
Will return the previously installed handler or Nil if one is not installed. Calling with Nil will return the old handler and clear it (no handler installed).
This special form will override breaking into the debugger when an error is raised.
Example:
(defmacro get-error-test (& body)
`(let (old-error (on-raised-error nil))
(defer (on-raised-error old-error))
(call/cc (fn (k) (on-raised-error (fn (err) (k (cons (car err)(cdr err)))))
(cons :ok (do ~@body))))))
(test::assert-equal (cons :ok 6) (get-error-test (let (x 1, y 5) (+ x y))))
(test::assert-equal '(:test . "error") (get-error-test (let (x 1, y 5) (err :test "error")(+ x y))))
quote
Usage: 'expression -> expression
Return expression without evaluation. The reader macro 'expression will expand to (quote expression).
Example:
(test::assert-equal (list 1 2 3) (quote (1 2 3)))
(test::assert-equal (list 1 2 3) '(1 2 3))
(test::assert-equal '(1 2 3) (quote (1 2 3)))
recur
Usage: (recur &rest)
Recursively call the enclosing function with the given parameters. Recur uses tail call optimization and must be in the tail position or it is an error. For a named function it would be equivalent to a normal recursive call in a tail position but it requires a tail position and does not need a name (a normal recursive call would work in a non-tail position but could blow the stack if it is to deep- unlike a recur or tail position recursive call). NOTE: potential footgun, the let macro expands to a lambda (fn) and a recur used inside the let would bind with the let not the enclosing lambda (this would apply to any macro that also expands to a lambda- this is by design with the loop macro but would be unexpected with let).
Example:
(def tot 0)
(loop (idx) (3) (do
(set! tot (+ tot 1))
(if (> idx 1) (recur (- idx 1)))))
(test::assert-equal 3 tot)
(set! tot 0)
((fn (idx) (do
(set! tot (+ tot 1))
(if (> idx 1) (recur (- idx 1)))))5)
(test::assert-equal 5 tot)
set!
Usage: (set! symbol expression) -> expression
Sets an existing expression in the current scope(s). Return the expression that was set. Symbol is not evaluated.
Set will set the first binding it finds starting in the current scope and then trying enclosing scopes until exhausted.
Example:
(def test-do-one nil)
(def test-do-two nil)
(def test-do-three (do (set! test-do-one "One")(set! test-do-two "Two")"Three"))
(test::assert-equal "One" test-do-one)
(test::assert-equal "Two" test-do-two)
(test::assert-equal "Three" test-do-three)
(let (test-do-one nil)
; set the currently scoped value.
(test::assert-equal "1111" (set! test-do-one "1111"))
(test::assert-equal "1111" test-do-one))
; Original outer scope not changed.
(test::assert-equal "One" test-do-one)
set-prop
Usage: (set-prop 'a-symbol :a-property a-value)
Write property with value for the given symbol.
Example:
(def foo #t)
(set-prop 'foo :bar "baz")
(test::assert-equal "baz" (get-prop 'foo :bar))
sizeof-heap-object
Usage: (sizeof-heap-object)
Returns the default size of a heap object by the current runtime in bytes.
Example:
(test::assert-equal 16 (sizeof-heap-object))
sizeof-value
Usage: (sizeof-value)
Returns the default size of a value by the current runtime in bytes. Optimized to be 8 bytes so that a given primitve or pointer to a head object fits in one word on a 64 bit machine.
Example:
(test::assert-equal 8 (sizeof-value))
substitute
Usage: (substitute lst old-item new-item mods)
Replaces all instances of old-item in copy of lst with new-item. If last argument passed in is keyword :first only the first instance of old-item will be replaced.
Example:
(let (lst (list 1 2 3 4 3)
olst (list 1 2 3 4 3)
lst2 (list 1 2 3 3 3 4 5)
olst2 (list 1 2 3 3 3 4 5))
(test::assert-equal (list 1 2 10 4 10) (substitute lst 3 10))
(test::assert-equal (list 1 2 10 4 3) (substitute lst 3 10 :first))
(test::assert-equal olst lst)
(test::assert-equal (list 1 2 4 4 4 4 5) (substitute lst2 3 4))
(test::assert-equal (list 1 2 4 3 3 4 5) (substitute lst2 3 4 :first))
(test::assert-equal olst2 lst2))
to-list
Usage: (to-list any)
Turns any one value into a list. If that value or if it was a sequence a new sequence with the same values.
No Examples
to-vec
Usage: (to-list any)
Turns any one value into a vector. If that value or if it was a sequence a new sequence with the same values.
No Examples
un-noop-fn
Usage: (un-noop-fn 'fn-to-un-noop)
If the runtime was previously altered for the provided function (to make it do nothing) swap the old function back in so the previous behavior is restored and the function behaves as normal.
Example:
#t
usage
Usage: (usage 'symbol)
Provides usage information derived from the bytecode. Documentation can also have it's own usage string provided in the doc string but this function returns what the actual function's compiled code provides.
No Examples
doc
List of symbols:
build-doc, doc-map, get-exemptions, get-globals-sorted, legacy_forms
build-doc
Usage: (build-doc valid-filepath)
Uses mdbook to build the documentation for the given book.
Example:
#t
doc-map
Usage: (doc-map symbol)
Returns documentation for given symbol as map. Keyword is a documentation fragment (usage, section, description, example) and value is text describing given fragment.
Example:
#t
get-exemptions
Usage: (get-exemptions)
Return a vector containing all the symbols currently exempted from docs (so the build passes), Ideally this will be 0.
No Examples
get-globals-sorted
Usage: (get-globals-sorted)
Return a vector containing all the symbols currently defined globally in sorted order (alphanumerically).
No Examples
legacy_forms
Usage: (legacy_forms)
Gets list of all forms that were used in the previous version of sl_sh.
Example:
#t
file
List of symbols:
cd, fclose, fflush, fopen, fs-accessed, fs-base, fs-crawl, fs-dir?, fs-exists?, fs-file?, fs-len, fs-modified, fs-parent, fs-rm, fs-same?, get-temp, get-temp-file, glob, read, read-all, read-line, temp-dir, with-temp, with-temp-file
cd
Usage: (cd dir-to-change-to)
Change directory.
Example:
(with-temp (fn (tmp)
(fclose (fopen (str tmp "/fs-cd-marker") :create :truncate))
(test::assert-false (fs-exists? "fs-cd-marker"))
(cd tmp)
(test::assert-true (fs-exists? "fs-cd-marker"))
(cd)))
fclose
Usage: (fclose file)
Close a file.
Example:
(with-temp-file (fn (tmp-file)
(let (tst-file (fopen tmp-file :create :truncate))
(fprn tst-file "Test Line Two")
(fclose tst-file)
(set! tst-file (fopen tmp-file :read))
(defer (fclose tst-file))
(test::assert-equal "Test Line Two
" (read-line tst-file)))))
fflush
Usage: (flush file)
Flush a file.
Example:
(with-temp-file (fn (tmp-file)
(let (tst-file (fopen tmp-file :create :truncate)
tst-file-read (fopen tmp-file :read))
(defer (fclose tst-file))
(defer (fclose tst-file-read))
(fprn tst-file "Test Line Three")
(fflush tst-file)
(test::assert-equal "Test Line Three
" (read-line tst-file-read)))))
fopen
Usage: (fopen filename option*)
Open a file. If you use :read and :write then you get a read/write unbuffered file. Including one of :read or :write will provide a file buffered for read or write (this is faster). Note: :append, :truncate, :create, :create-new all imply :write.
Options are: :read :write :append :truncate :create :create-new :on-error-nil
Example:
(with-temp-file (fn (tmp-file)
(let (test-open-f (fopen tmp-file :create :truncate))
(fprn test-open-f "Test Line One")
(fclose test-open-f)
(set! test-open-f (fopen tmp-file :read))
(defer (fclose test-open-f))
(test::assert-equal "Test Line One
" (read-line test-open-f)))))
fs-accessed
Usage: (fs-accessed /path/to/file/or/dir)
Returns the unix time file last accessed in ms.
Example:
(with-temp-file (fn (tmp)
(let (tst-file (fopen tmp :create)
last-acc (fs-accessed tmp))
(fclose tst-file)
(let (tst-file (fopen tmp :read))
(test::assert-true (>= (fs-accessed tmp) last-acc))
(fclose tst-file)))))
fs-base
Usage: (fs-base /path/to/file/or/dir)
Returns base name of file or directory passed to function.
No Examples
fs-crawl
Usage: (fs-crawl /path/to/file/or/dir (fn (x) (prn "found path" x) [max-depth] [:follow-syms])
If a directory is provided the path is recursively searched and every file and directory is called as an argument to the provided function. If a file is provided the path is provided as an argument to the provided function. Takes two optional arguments (in any order) an integer, representing max depth to traverse if file is a directory, or the symbol, :follow-syms, to follow symbol links when traversing if desired.
Example:
(with-temp-file (fn (tmp-file)
(let (cnt 0)
(fs-crawl tmp-file (fn (x)
(test::assert-equal (fs-base tmp-file) (fs-base x))
(set! cnt (+ 1 cnt))))
(test::assert-equal 1 cnt))))
(defn create-in (in-dir num-files visited)
(dotimes-i i num-files
(let (tmp-file (get-temp-file in-dir))
(set! visited.~tmp-file #f))))
(defn create-dir (tmp-dir visited)
(let (new-tmp (get-temp tmp-dir))
(set! visited.~new-tmp #f)
new-tmp))
(with-temp (fn (root-tmp-dir)
(let (tmp-file-count 5
visited {}
cnt 0)
(set! visited.~root-tmp-dir #f)
(create-in root-tmp-dir tmp-file-count visited)
(let (tmp-dir (create-dir root-tmp-dir visited)
new-files (create-in tmp-dir tmp-file-count visited)
tmp-dir (create-dir tmp-dir visited)
new-files (create-in tmp-dir tmp-file-count visited))
(fs-crawl root-tmp-dir (fn (x)
(let (file visited.~x)
(test::assert-true (not file)) ;; also tests double counting
(set! visited.~x #t)
(inc! cnt))))
(test::assert-equal (+ 3 (* 3 tmp-file-count)) cnt)
(test::assert-equal (+ 3 (* 3 tmp-file-count)) (len visited))
(seq-for key in (hash-keys visited) (test::assert-true visited.~key))))))
(with-temp (fn (root-tmp-dir)
(let (tmp-file-count 5
visited {}
cnt 0)
(set! visited.~root-tmp-dir #f)
(create-in root-tmp-dir tmp-file-count visited)
(let (tmp-dir (create-dir root-tmp-dir visited)
new-files (create-in tmp-dir tmp-file-count visited)
tmp-dir (create-dir tmp-dir {})
new-files (do (set! visited.~tmp-dir #f)(create-in tmp-dir tmp-file-count {})))
(fs-crawl root-tmp-dir (fn (x)
(let (file visited.~x)
(test::assert-true (not file)) ;; also tests double counting
(set! visited.~x #t)
(inc! cnt))) 2)
(test::assert-equal (+ 3 (* 2 tmp-file-count)) cnt)
(test::assert-equal (+ 3 (* 2 tmp-file-count)) (len visited))
(seq-for key in (hash-keys visited) (test::assert-true visited.~key))))))
(with-temp (fn (root-tmp-dir)
(let (tmp-file-count 5
visited {}
cnt 0)
(set! visited.~root-tmp-dir #f)
(create-in root-tmp-dir tmp-file-count visited)
(let (tmp-dir (create-dir root-tmp-dir {})
new-files (do (set! visited.~tmp-dir #f)(create-in tmp-dir tmp-file-count {}))
tmp-dir (create-dir tmp-dir {})
new-files (create-in tmp-dir tmp-file-count {}))
(fs-crawl root-tmp-dir (fn (x)
(let (file visited.~x)
(test::assert-true (not file)) ;; also tests double counting
(set! visited.~x #t)
(inc! cnt))) 1)
(test::assert-equal (+ 2 tmp-file-count) cnt)
(test::assert-equal (+ 2 tmp-file-count) (len visited))
(seq-for key in (hash-keys visited) (test::assert-true visited.~key))))))
fs-dir?
Usage: (fs-dir? path-to-test)
Is the given path a directory?
Example:
(with-temp (fn (tmp)
(fclose (fopen (str tmp "/fs-dir-file") :create :truncate))
(test::assert-false (fs-dir? (str tmp "/fs-dir-file")))
(test::assert-true (fs-dir? tmp))
(test::assert-false (fs-file? (str tmp "/fs-dir-nope")))))
fs-exists?
Usage: (fs-exists? path-to-test)
Does the given path exist?
Example:
(with-temp (fn (tmp)
(fclose (fopen (str tmp "/fs-exists") :create :truncate))
(test::assert-true (fs-exists? (str tmp "/fs-exists")))
(test::assert-true (fs-exists? tmp))
(test::assert-false (fs-exists? (str tmp "/fs-exists-nope")))))
fs-file?
Usage: (fs-file? path-to-test)
Is the given path a file?
Example:
(with-temp (fn (tmp)
(fclose (fopen (str tmp "/fs-file") :create :truncate))
(test::assert-true (fs-file? (str tmp "/fs-file")))
(test::assert-false (fs-file? tmp))
(test::assert-false (fs-file? (str tmp "/fs-file-nope")))))
fs-len
Usage: (fs-len /path/to/file/or/dir)
Returns the size of the file in bytes.
Example:
(with-temp-file (fn (tmp)
(let (tst-file (fopen tmp :create :truncate))
(fprn tst-file "Test Line Read Line One")
(fpr tst-file "Test Line Read Line Two")
(fclose tst-file)
(test::assert-equal 47 (fs-len tmp)))))
fs-modified
Usage: (fs-modified /path/to/file/or/dir)
Returns the unix time file last modified in ms.
Example:
(with-temp-file (fn (tmp)
(let (tst-file (fopen tmp :create :truncate)
last-mod (fs-modified tmp))
(fprn tst-file "Test Line Read Line One")
(fpr tst-file "Test Line Read Line Two")
(fflush tst-file)
(fclose tst-file)
(test::assert-true (>= (fs-modified tmp) last-mod)))))
fs-parent
Usage: (fs-parent /path/to/file/or/dir)
Returns base name of file or directory passed to function.
No Examples
fs-rm
Usage: (fs-rm "/dir/or/file/to/remove")
Takes a file or directory as a string and removes it. Works recursively for directories.
Example:
(def fp nil)
(let (a-file (get-temp-file))
(test::assert-true (fs-exists? a-file))
(set! fp a-file)
(fs-rm a-file))
(test::assert-false (nil? fp))
(test::assert-false (fs-exists? fp))
fs-same?
Usage: (fs-same? /path/to/file/or/dir /path/to/file/or/dir)
Returns true if the two provided file paths refer to the same file or directory.
Example:
(with-temp-file (fn (tmp-file)
(test::assert-true (fs-same? tmp-file tmp-file))))
get-temp
Usage: (get-temp ["/path/to/directory/to/use/as/base" "optional-prefix" "optional-suffix" length])
Creates a directory inside of an OS specific temporary directory. See temp-dir for OS specific notes. Also accepts an optional prefix, an optional suffix, and an optional length for the random number of characters in the temporary file created. Defaults to prefix of ".tmp", no suffix, and five random characters.
Example:
(test::assert-true (str-contains (get-temp) (temp-dir)))
(with-temp (fn (tmp)
(let (tmp-dir (get-temp tmp))
(test::assert-true (str-contains tmp-dir tmp)))))
(with-temp (fn (tmp)
(let (tmp-dir (get-temp tmp "some-prefix"))
(test::assert-true (str-contains tmp-dir tmp))
(test::assert-true (str-contains tmp-dir "some-prefix")))))
(with-temp (fn (tmp)
(let (tmp-dir (get-temp tmp "some-prefix" "some-suffix"))
(test::assert-true (str-contains tmp-dir tmp))
(test::assert-true (str-contains tmp-dir "some-prefix"))
(test::assert-true (str-contains tmp-dir "some-suffix")))))
(with-temp (fn (tmp)
(let (tmp-dir (get-temp tmp "some-prefix" "some-suffix" 6))
(test::assert-true (str-contains tmp-dir tmp))
(test::assert-true (str-contains tmp-dir "some-prefix"))
(test::assert-true (str-contains tmp-dir "some-suffix"))
(test::assert-equal (len "some-prefix012345some-suffix") (len (fs-base tmp-dir))))))
get-temp-file
Usage: (get-temp-file ["/path/to/directory/to/use/as/base" "optional-prefix" "optional-suffix" length])
Returns name of file created inside temporary directory. Optionally takes a directory to use as the parent directory of the temporary file. Also accepts an optional prefix, an optional suffix, and an optional length for the random number of characters in the temporary files created. Defaults to prefix of ".tmp", no suffix, and five random characters.
Example:
(test::assert-true (str-contains (get-temp-file) (temp-dir)))
(with-temp (fn (tmp)
(let (tmp-file (get-temp-file tmp))
(test::assert-true (str-contains tmp-file tmp)))))
(with-temp (fn (tmp)
(let (tmp-file (get-temp-file tmp "some-prefix"))
(test::assert-true (str-contains tmp-file "some-prefix")))))
(with-temp (fn (tmp)
(let (tmp-file (get-temp-file tmp "some-prefix" "some-suffix"))
(test::assert-true (str-contains tmp-file "some-prefix"))
(test::assert-true (str-contains tmp-file "some-suffix")))))
(with-temp (fn (tmp)
(let (tmp-file (get-temp-file tmp "some-prefix" "some-suffix" 10))
(test::assert-true (str-contains tmp-file "some-prefix"))
(test::assert-true (str-contains tmp-file "some-suffix"))
(test::assert-equal (len "some-prefix0123456789some-suffix") (len (fs-base tmp-file))))))
glob
Usage: (glob /path/with/*)
Takes a list/varargs of globs and return the list of them expanded.
Example:
(with-temp (fn (tmp)
(fclose (fopen (str tmp "/g1") :create :truncate))
(fclose (fopen (str tmp "/g2") :create :truncate))
(fclose (fopen (str tmp "/g3") :create :truncate))
(test::assert-equal [(str tmp "/g1") (str tmp "/g2") (str tmp "/g3")] (glob (str tmp "/*")))))
read
Usage: (read file|string end-exp?) -> expression
Read a file or string and return the next object (symbol, string, list, etc). Raises an error if the file or string has been read unless end-exp is provided then returns that on the end condition. Note: When reading a string read always starts at the beginning of the string.
Example:
(with-temp-file (fn (tmp)
(let (tst-file (fopen tmp :create :truncate)
test-str nil)
(fprn tst-file "(1 2 3)(x y z)")
(fclose tst-file)
(set! tst-file (fopen tmp :read))
(test::assert-equal '(1 2 3) (read tst-file))
(test::assert-equal '(x y z) (read tst-file))
(test::assert-error (read tst-file))
(fclose tst-file)
(set! tst-file (fopen tmp :read))
(test::assert-equal '(1 2 3) (read tst-file :done))
(test::assert-equal '(x y z) (read tst-file :done))
(test::assert-equal :done (read tst-file :done))
(fclose tst-file)
(test::assert-equal '(4 5 6) (read "(4 5 6)"))
(set! test-str "7 8 9")
(test::assert-equal 7 (read test-str))
(test::assert-equal 7 (read test-str))
(test::assert-equal '(x y z) (read "(x y z)")))))
read-all
Usage: (read-all file|string) -> vec
Read a file or string and return the vector of contained expressions. This reads the entire file or string and will wrap it in an outer vector (always returns a vector).
Unlike most lisp readers this one will put loose symbols in a vector (i.e. you enter things at the repl without the enclosing parens).
If the read item is empty (including a comment) then will return an empty vector.
Example:
(with-temp-file (fn (tmp)
(let (tst-file (fopen tmp :create :truncate)
test-str nil)
(fprn tst-file "(1 2 3)(x y z)")
(fclose tst-file)
(set! tst-file (fopen tmp :read))
(test::assert-equal ['(1 2 3)'(x y z)] (read-all tst-file))
(fclose tst-file)
(test::assert-equal ['(4 5 6)] (read-all "(4 5 6)"))
(test::assert-equal [7 8 9] (read-all "7 8 9"))
(test::assert-equal ['(x y z)] (read-all "(x y z)"))
(test::assert-equal [] (read-all ";(x y z)")))))
read-line
Usage: (read-line file) -> string
Read a line from a file. Returns Nil if there is nothing left to read.
Example:
(with-temp-file (fn (tmp)
(let (tst-file (fopen tmp :create :truncate))
(fprn tst-file "Test Line Read Line One")
(fpr tst-file "Test Line Read Line Two")
(fclose tst-file)
(set! tst-file (fopen tmp :read))
(defer (fclose tst-file))
(test::assert-equal "Test Line Read Line One\n" (read-line tst-file))
(test::assert-equal "Test Line Read Line Two" (read-line tst-file)))))
temp-dir
Usage: (temp-dir)
Returns a string representing the temporary directory. See get-temp for higher level temporary directory creation mechanism.
On Unix: Returns the value of the TMPDIR environment variable if it is set, otherwise for non-Android it returns /tmp. If Android, since there is no global temporary folder (it is usually allocated per-app), it returns /data/local/tmp.
On Windows: Returns the value of, in order, the TMP, TEMP, USERPROFILE environment variable if any are set and not the empty string. Otherwise, temp_dir returns the path of the Windows directory. This behavior is identical to that of GetTempPath, which this function uses internally.
Example:
(test::assert-true (fs-dir? (temp-dir)))
with-temp
Usage: (with-temp (fn (x) (println "given temp dir:" x)) ["optional-prefix" "optional-suffix" length])
Takes a function that accepts a temporary directory. This directory will be recursively removed when the provided function is finished executing. Also accepts an optional prefix, an optional suffix, and an optional length for the random number of characters in the temporary directory created. Defaults to prefix of ".tmp", no suffix, and five random characters.
Example:
(def fp nil)
(with-temp (fn (tmp-dir)
(let (tmp-file (str tmp-dir "/sl-sh-tmp-file.txt")
a-file (fopen tmp-file :create :truncate))
(test::assert-true (fs-exists? tmp-file))
(set! fp tmp-file)
(fclose a-file))))
(test::assert-false (nil? fp))
(test::assert-false (fs-exists? fp))
(with-temp
(fn (tmp)
(test::assert-true (str-contains tmp "some-prefix")))
"some-prefix")
(with-temp
(fn (tmp)
(test::assert-true (str-contains tmp "some-prefix"))
(test::assert-true (str-contains tmp "some-suffix")))
"some-prefix"
"some-suffix")
(with-temp
(fn (tmp)
(test::assert-true (str-contains tmp "some-prefix"))
(test::assert-true (str-contains tmp "some-suffix"))
(test::assert-equal (len "some-prefix0123456789some-suffix") (len (fs-base tmp))))
"some-prefix"
"some-suffix"
10)
with-temp-file
Usage: (with-temp-file (fn (x) (println "given temp file:" x)) ["optional-prefix" "optional-suffix" length])
Takes a function that accepts a temporary file. This file will be removed when the provided function is finished executing. Also accepts an optional prefix, an optional suffix, and an optional length for the random number of characters in the temporary file created. Defaults to prefix of ".tmp", no suffix, and five random characters.
Example:
(def fp nil)
(with-temp-file (fn (tmp-file)
(let (a-file (fopen tmp-file :create :truncate))
(test::assert-true (fs-exists? tmp-file))
(set! fp tmp-file)
(fclose a-file))))
(test::assert-false (nil? fp))
(test::assert-false (fs-exists? fp))
(with-temp-file
(fn (tmp)
(test::assert-true (str-contains tmp "some-prefix")))
"some-prefix")
(with-temp-file
(fn (tmp)
(test::assert-true (str-contains tmp "some-prefix"))
(test::assert-true (str-contains tmp "some-suffix")))
"some-prefix"
"some-suffix")
(with-temp-file
(fn (tmp)
(test::assert-true (str-contains tmp "some-prefix"))
(test::assert-true (str-contains tmp "some-suffix"))
(test::assert-equal (len "some-prefix0123456789some-suffix") (len (fs-base tmp))))
"some-prefix"
"some-suffix"
10)
hashmap
Hashmaps as a collection benefit from the same syntactic sugar provided by the
reader macro with the added support of some generic collection functions, get
,
set!
, and clear!
.
For retrieving items from a hashmap prefer the reader syntax (
(def m {:one "one", :two "two", "three" 3})
(and (= "one" m.:one)
(= "two" m.:two)
(= 3 (get m "three")))
;; => true
For setting key/value pairs on an existing hashmap prefer the reader syntax
with the set!
function or pass it the output of get
.
(def m {:one "one", :two "two", "three" 3, :four 4})
(set! m.:one "changed1")
(set! m.:two "changed2")
(set! (get m "three") "changed3")
(and (= "changed1" m.:one)
(= "changed2" m.:two)
(= "changed3" (get m "three")))
(def four :four)
(set! m.~four "changed4")
(= "changed4" (get m :four))
;; => true
Clearing all keys is done with the clear!
function.
(def m {:one "one", :two "two", "three" 3})
(clear! m)
(= (make-hash) m)
;; => true
** Hashmap keys that are not keyword types (not prefixed by a colon) can not be
used with the reader syntax, which is why in the example the key "three" was
used with the get
function each time instead of using the reader syntax.
List of symbols:
hash-keys, hash-remove!, make-hash
hash-keys
Usage: (hash-keys hashmap)
Returns a vector of all the hashmaps keys. The keys will be unordered.
Example:
(def tst-hash {:key1 "val one" 'key2 "val two" "key3" "val three" \S "val S"})
(test::assert-equal 4 (len (hash-keys tst-hash)))
(test::assert-true (in? (hash-keys tst-hash) :key1) " Test :key1")
(test::assert-true (in? (hash-keys tst-hash) 'key2) " Test key2")
(test::assert-true (in? (hash-keys tst-hash) \S) " Test S")
(test::assert-true (in? (hash-keys tst-hash) "key3") " Test key3")
(test::assert-false (in? (hash-keys tst-hash) :key4))
hash-remove!
Usage: (hash-remove! hashmap key)
Remove a key from a hashmap. This is a destructive form!
Example:
(def tst-hash {:key1 "val one" 'key2 "val two" "key3" "val three" \S "val S"})
(test::assert-equal 4 (len (hash-keys tst-hash)))
(test::assert-equal "val one" tst-hash.:key1)
(test::assert-equal "val two" (get tst-hash 'key2))
(test::assert-equal "val three" (get tst-hash "key3"))
(test::assert-equal "val S" (get tst-hash \S))
(hash-remove! tst-hash 'key2)
(test::assert-equal 3 (len (hash-keys tst-hash)))
(test::assert-equal "val one" tst-hash.:key1)
(test::assert-equal "val three" (get tst-hash "key3"))
(test::assert-equal "val S" (get tst-hash \S))
(hash-remove! tst-hash :key1)
(test::assert-equal 2 (len (hash-keys tst-hash)))
(test::assert-equal "val three" (get tst-hash "key3"))
(test::assert-equal "val S" (get tst-hash \S))
(hash-remove! tst-hash "key3")
(test::assert-equal 1 (len (hash-keys tst-hash)))
(test::assert-equal "val S" (get tst-hash \S))
(hash-remove! tst-hash \S)
(test::assert-equal 0 (len (hash-keys tst-hash)))
make-hash
Usage: (make-hash associations?)
Make a new hash map.
If associations is provided (makes an empty map if not) then it is a list of pairs (key . value) that populate the initial map. Neither key nor value in the associations will be evaluated.
No Examples
io
List of symbols:
fs-meta
Usage: (fs-meta [FILENAME]) -> map
Returns a map of a files meta data.
No Examples
iterator
List of symbols:
iter::enumerate, iter::file-iter, iter::filter, iter::for, iter::iter, iter::iter-or-single, iter::iter?, iter::list-iter, iter::map, iter::mk-iter, iter::once-iter, iter::range, iter::reduce, iter::repeat-iter, iter::string-iter, iter::vec-iter, iter::vec-iter-pair, iter::vec-iter-rev, iter::enumerate, iter::file-iter, iter::filter, iter::for, iter::iter, iter::iter-or-single, iter::iter?, iter::list-iter, iter::map, iter::mk-iter, iter::once-iter, iter::range, iter::reduce, iter::repeat-iter, iter::string-iter, iter::vec-iter, iter::vec-iter-pair, iter::vec-iter-rev
iter::enumerate
Usage: (iter::enumerate iter start [SCRATCH] [SCRATCH] idx [SCRATCH] [SCRATCH] iter)
Iterator that wraps an iterator and generates pairs of current index and value. Index is 0 based by default, takes an optional second parameter with the start index.
Example:
(import iter)
(let (test-iter (enumerate (vec-iter [:a :b :c])))
(let ([i v] (test-iter)) (test::assert-equal 0 i) (test::assert-equal :a v))
(let ([i v] (test-iter)) (test::assert-equal 1 i) (test::assert-equal :b v))
(let ([i v] (test-iter)) (test::assert-equal 2 i) (test::assert-equal :c v))
(test::assert-equal :*iter-empty* (test-iter)))
(let (test-iter (enumerate (vec-iter [:a :b :c]) 5))
(let ([i v] (test-iter)) (test::assert-equal 5 i) (test::assert-equal :a v))
(let ([i v] (test-iter)) (test::assert-equal 6 i) (test::assert-equal :b v))
(let ([i v] (test-iter)) (test::assert-equal 7 i) (test::assert-equal :c v))
(test::assert-equal :*iter-empty* (test-iter)))
iter::file-iter
Usage: (iter::file-iter f [SCRATCH] [SCRATCH] iter)
Iterator that wraps a file. Each call produces the next line (with trailing newline).
Example:
(import iter)
(with-temp-file (fn (file-name)
(let (tst-file (fopen file-name :create :truncate))
(defer (fclose tst-file))
(fprn tst-file "line 1")
(fprn tst-file "line 2")
(fprn tst-file "line 3")
(fpr tst-file "line 4"))
(let (tst-file (fopen file-name), test-iter (file-iter tst-file))
(defer (fclose tst-file))
(test::assert-equal "line 1\n" (test-iter))
(test::assert-equal "line 2\n" (test-iter))
(test::assert-equal "line 3\n" (test-iter))
(test::assert-equal "line 4" (test-iter))
(test::assert-equal :*iter-empty* (test-iter)))))
iter::filter
Usage: (iter::filter iter lambda [SCRATCH] [SCRATCH] iter)
Returns a filter-iter around iter. Iterator that applies a lambda to each element to determine if is returned- is lazy.
Example:
(let (test-iter (iter::filter (iter::vec-iter [1 2 3]) (fn (x) (not (= x 2)))))
(test::assert-equal 1 (test-iter))
(test::assert-equal 3 (test-iter))
(test::assert-equal :*iter-empty* (test-iter)))
iter::for
Usage: (iter::for bind in items body [SCRATCH] [SCRATCH] i-name actual-bind)
Loops over each element in an iterator. The bind parameter is bound to the current element of items and is accessible in body. Body is evaluated a number of times equal to the items in the iterator.
Example:
(import iter)
(let (i 0)
(for x in (range 0 11) (set! i (+ 1 i)))
(test::assert-equal 11 i))
(let (v [:a :b :c], iter (enumerate (vec-iter v)))
(for [idx, val] in iter (test::assert-equal v.~idx val)))
iter::iter
Usage: (iter::iter thing)
Return thing as an iterator if possible (if it is an iterator just return thing).
Example:
(import iter)
(test::assert-true (iter? (iter '(1 2 3))))
(test::assert-true (iter? (iter [1 2 3])))
(test::assert-true (iter? (iter "abc")))
(test::assert-true (iter? (iter (iter '(1 2 3)))))
iter::iter-or-single
Usage: (iter::iter-or-single thing)
Return thing as an iterator if possible (if it is an iterator just return thing). If not possible then wrap thing in a once iter and return that.
Example:
(import iter)
(test::assert-true (iter? (iter-or-single '(1 2 3))))
(test::assert-true (iter? (iter-or-single [1 2 3])))
(test::assert-true (iter? (iter-or-single "abc")))
(test::assert-true (iter? (iter-or-single (iter '(1 2 3)))))
(test::assert-true (iter? (iter-or-single 1)))
(test::assert-true (iter? (iter-or-single \A)))
iter::iter?
Usage: (iter::iter? test)
Return true if thing is an iterator, false otherwise.
Example:
(import iter)
(test::assert-true (iter? (list-iter '(1 2 3))))
(test::assert-false (iter? '(1 2 3)))
iter::list-iter
Usage: (iter::list-iter l [SCRATCH] [SCRATCH] iter)
Iterator that wraps a list.
Example:
(import iter)
(let (test-list-iter (list-iter '(1 2 3)))
(test::assert-equal 1 (test-list-iter))
(test::assert-equal 2 (test-list-iter))
(test::assert-equal 3 (test-list-iter))
(test::assert-equal :*iter-empty* (test-list-iter))
(set! test-list-iter (list-iter '()))
(test::assert-equal :*iter-empty* (test-list-iter)))
iter::map
Usage: (iter::map i lambda [SCRATCH] [SCRATCH] iter)
Iterator that applies a lambda to each element of another iterator- is lazy.
Example:
(import iter)
(let (test-map-iter (map (list-iter '(1 2 3)) (fn (x) (* x 2))))
(test::assert-equal 2 (test-map-iter))
(test::assert-equal 4 (test-map-iter))
(test::assert-equal 6 (test-map-iter))
(test::assert-equal :*iter-empty* (test-map-iter)))
iter::mk-iter
Usage: (iter::mk-iter body)
Helper to create an iterator. Will make sure it has the correct property set.
Example:
iter::once-iter
Usage: (iter::once-iter i [SCRATCH] [SCRATCH] iter)
Iterator that wraps and returns a single object once.
Example:
(import iter)
(let (test-iter (once-iter 3))
(test::assert-equal 3 (test-iter))
(test::assert-equal :*iter-empty* (test-iter))
(set! test-iter (once-iter "iter"))
(test::assert-equal "iter" (test-iter))
(test::assert-equal :*iter-empty* (test-iter)))
iter::range
Usage: (iter::range start end [SCRATCH] [SCRATCH] iter)
Iterator that generates numbers within a range.
Example:
(import iter)
(let (test-iter (range 3 6))
(test::assert-equal 3 (test-iter))
(test::assert-equal 4 (test-iter))
(test::assert-equal 5 (test-iter))
(test::assert-equal :*iter-empty* (test-iter)))
iter::reduce
Usage: (iter::reduce iter acc reducing-fn [SCRATCH] [SCRATCH] #SYM:367:0 #SYM:367:1 #SYM:367:1 [SCRATCH] val)
reduce is used to amalgamate an iterator and an initial value, according to the reducing function provided. The reducing-fcn should be a function of two arguments. In the first iteration of reduce, the init-val will be used as the first argument to the reducing-fcn and (iter) will be used as the second argument. For all subsequent iterations, The result from the previous application of the reducing-fcn will be used as the first argument to the reducing-fcn and the second argument will be the next item in the collection when the collection is empty reduce will return the amalgamated result.
Example:
(import iter)
(test::assert-true (= 15 (iter::reduce (iter::vec-iter [1 2 3 4 5]) 0 +)))
(test::assert-true (= 16 (iter::reduce (iter::vec-iter [1 2 3 4 5]) 1 +)))
(test::assert-true (= "one hoopy frood" (iter::reduce (iter::vec-iter ["one " "hoopy " "frood"]) "" str)))
iter::repeat-iter
Usage: (iter::repeat-iter i [SCRATCH] [SCRATCH] iter)
Iterator that wraps and returns a single object on each call.
Example:
(import iter)
(let (test-iter (repeat-iter 3))
(test::assert-equal 3 (test-iter))
(test::assert-equal 3 (test-iter))
(test::assert-equal 3 (test-iter))
(test::assert-equal 3 (test-iter))
(test::assert-equal 3 (test-iter))
(set! test-iter (repeat-iter "iter"))
(test::assert-equal "iter" (test-iter))
(test::assert-equal "iter" (test-iter))
(test::assert-equal "iter" (test-iter))
(test::assert-equal "iter" (test-iter))
(test::assert-equal "iter" (test-iter)))
iter::string-iter
Usage: (iter::string-iter s [SCRATCH] [SCRATCH] idx slen [SCRATCH] [SCRATCH] iter)
Iterator that wraps a string. Each element is the next character.
Example:
(import iter)
(let (test-string-iter (string-iter "123"))
(test::assert-equal \1 (test-string-iter))
(test::assert-equal \2 (test-string-iter))
(test::assert-equal \3 (test-string-iter))
(test::assert-equal :*iter-empty* (test-string-iter)))
iter::vec-iter
Usage: (iter::vec-iter v [SCRATCH] [SCRATCH] idx vlen [SCRATCH] [SCRATCH] iter)
Iterator that wraps a vector.
Example:
(import iter)
(let (test-vec-iter (vec-iter [1 2 3]))
(test::assert-equal 1 (test-vec-iter))
(test::assert-equal 2 (test-vec-iter))
(test::assert-equal 3 (test-vec-iter))
(test::assert-equal :*iter-empty* (test-vec-iter))
(set! test-vec-iter (vec-iter (vec)))
(test::assert-equal :*iter-empty* (test-vec-iter)))
iter::vec-iter-pair
Usage: (iter::vec-iter-pair v [SCRATCH] [SCRATCH] fidx bidx [SCRATCH] [SCRATCH] iter iter)
Return a pair of iterators, one forward and one reverse for a vector. The two iterators will not overlap (i.e. the forward and reverse will never produce the same items).
Example:
(import iter)
(let ([fwd-iter, rev-iter] (vec-iter-pair [1 2 3]))
(test::assert-equal 1 (fwd-iter))
(test::assert-equal 3 (rev-iter))
(test::assert-equal 2 (fwd-iter))
(test::assert-equal :*iter-empty* (rev-iter))
(test::assert-equal :*iter-empty* (fwd-iter)))
(let ([fwd-iter, rev-iter] (vec-iter-pair (vec)))
(test::assert-equal :*iter-empty* (fwd-iter))
(test::assert-equal :*iter-empty* (rev-iter)))
iter::vec-iter-rev
Usage: (iter::vec-iter-rev v [SCRATCH] [SCRATCH] idx [SCRATCH] [SCRATCH] iter)
Iterator produces a vector in reverse.
Example:
(import iter)
(let (test-vec-iter (vec-iter-rev [1 2 3]))
(test::assert-equal 3 (test-vec-iter))
(test::assert-equal 2 (test-vec-iter))
(test::assert-equal 1 (test-vec-iter))
(test::assert-equal :*iter-empty* (test-vec-iter))
(set! test-vec-iter (vec-iter-rev (vec)))
(test::assert-equal :*iter-empty* (test-vec-iter)))
iter::enumerate
Usage: (iter::enumerate iter start [SCRATCH] [SCRATCH] idx [SCRATCH] [SCRATCH] iter)
Iterator that wraps an iterator and generates pairs of current index and value. Index is 0 based by default, takes an optional second parameter with the start index.
Example:
(import iter)
(let (test-iter (enumerate (vec-iter [:a :b :c])))
(let ([i v] (test-iter)) (test::assert-equal 0 i) (test::assert-equal :a v))
(let ([i v] (test-iter)) (test::assert-equal 1 i) (test::assert-equal :b v))
(let ([i v] (test-iter)) (test::assert-equal 2 i) (test::assert-equal :c v))
(test::assert-equal :*iter-empty* (test-iter)))
(let (test-iter (enumerate (vec-iter [:a :b :c]) 5))
(let ([i v] (test-iter)) (test::assert-equal 5 i) (test::assert-equal :a v))
(let ([i v] (test-iter)) (test::assert-equal 6 i) (test::assert-equal :b v))
(let ([i v] (test-iter)) (test::assert-equal 7 i) (test::assert-equal :c v))
(test::assert-equal :*iter-empty* (test-iter)))
iter::file-iter
Usage: (iter::file-iter f [SCRATCH] [SCRATCH] iter)
Iterator that wraps a file. Each call produces the next line (with trailing newline).
Example:
(import iter)
(with-temp-file (fn (file-name)
(let (tst-file (fopen file-name :create :truncate))
(defer (fclose tst-file))
(fprn tst-file "line 1")
(fprn tst-file "line 2")
(fprn tst-file "line 3")
(fpr tst-file "line 4"))
(let (tst-file (fopen file-name), test-iter (file-iter tst-file))
(defer (fclose tst-file))
(test::assert-equal "line 1\n" (test-iter))
(test::assert-equal "line 2\n" (test-iter))
(test::assert-equal "line 3\n" (test-iter))
(test::assert-equal "line 4" (test-iter))
(test::assert-equal :*iter-empty* (test-iter)))))
iter::filter
Usage: (iter::filter iter lambda [SCRATCH] [SCRATCH] iter)
Returns a filter-iter around iter. Iterator that applies a lambda to each element to determine if is returned- is lazy.
Example:
(let (test-iter (iter::filter (iter::vec-iter [1 2 3]) (fn (x) (not (= x 2)))))
(test::assert-equal 1 (test-iter))
(test::assert-equal 3 (test-iter))
(test::assert-equal :*iter-empty* (test-iter)))
iter::for
Usage: (iter::for bind in items body [SCRATCH] [SCRATCH] i-name actual-bind)
Loops over each element in an iterator. The bind parameter is bound to the current element of items and is accessible in body. Body is evaluated a number of times equal to the items in the iterator.
Example:
(import iter)
(let (i 0)
(for x in (range 0 11) (set! i (+ 1 i)))
(test::assert-equal 11 i))
(let (v [:a :b :c], iter (enumerate (vec-iter v)))
(for [idx, val] in iter (test::assert-equal v.~idx val)))
iter::iter
Usage: (iter::iter thing)
Return thing as an iterator if possible (if it is an iterator just return thing).
Example:
(import iter)
(test::assert-true (iter? (iter '(1 2 3))))
(test::assert-true (iter? (iter [1 2 3])))
(test::assert-true (iter? (iter "abc")))
(test::assert-true (iter? (iter (iter '(1 2 3)))))
iter::iter-or-single
Usage: (iter::iter-or-single thing)
Return thing as an iterator if possible (if it is an iterator just return thing). If not possible then wrap thing in a once iter and return that.
Example:
(import iter)
(test::assert-true (iter? (iter-or-single '(1 2 3))))
(test::assert-true (iter? (iter-or-single [1 2 3])))
(test::assert-true (iter? (iter-or-single "abc")))
(test::assert-true (iter? (iter-or-single (iter '(1 2 3)))))
(test::assert-true (iter? (iter-or-single 1)))
(test::assert-true (iter? (iter-or-single \A)))
iter::iter?
Usage: (iter::iter? test)
Return true if thing is an iterator, false otherwise.
Example:
(import iter)
(test::assert-true (iter? (list-iter '(1 2 3))))
(test::assert-false (iter? '(1 2 3)))
iter::list-iter
Usage: (iter::list-iter l [SCRATCH] [SCRATCH] iter)
Iterator that wraps a list.
Example:
(import iter)
(let (test-list-iter (list-iter '(1 2 3)))
(test::assert-equal 1 (test-list-iter))
(test::assert-equal 2 (test-list-iter))
(test::assert-equal 3 (test-list-iter))
(test::assert-equal :*iter-empty* (test-list-iter))
(set! test-list-iter (list-iter '()))
(test::assert-equal :*iter-empty* (test-list-iter)))
iter::map
Usage: (iter::map i lambda [SCRATCH] [SCRATCH] iter)
Iterator that applies a lambda to each element of another iterator- is lazy.
Example:
(import iter)
(let (test-map-iter (map (list-iter '(1 2 3)) (fn (x) (* x 2))))
(test::assert-equal 2 (test-map-iter))
(test::assert-equal 4 (test-map-iter))
(test::assert-equal 6 (test-map-iter))
(test::assert-equal :*iter-empty* (test-map-iter)))
iter::mk-iter
Usage: (iter::mk-iter body)
Helper to create an iterator. Will make sure it has the correct property set.
Example:
iter::once-iter
Usage: (iter::once-iter i [SCRATCH] [SCRATCH] iter)
Iterator that wraps and returns a single object once.
Example:
(import iter)
(let (test-iter (once-iter 3))
(test::assert-equal 3 (test-iter))
(test::assert-equal :*iter-empty* (test-iter))
(set! test-iter (once-iter "iter"))
(test::assert-equal "iter" (test-iter))
(test::assert-equal :*iter-empty* (test-iter)))
iter::range
Usage: (iter::range start end [SCRATCH] [SCRATCH] iter)
Iterator that generates numbers within a range.
Example:
(import iter)
(let (test-iter (range 3 6))
(test::assert-equal 3 (test-iter))
(test::assert-equal 4 (test-iter))
(test::assert-equal 5 (test-iter))
(test::assert-equal :*iter-empty* (test-iter)))
iter::reduce
Usage: (iter::reduce iter acc reducing-fn [SCRATCH] [SCRATCH] #SYM:367:0 #SYM:367:1 #SYM:367:1 [SCRATCH] val)
reduce is used to amalgamate an iterator and an initial value, according to the reducing function provided. The reducing-fcn should be a function of two arguments. In the first iteration of reduce, the init-val will be used as the first argument to the reducing-fcn and (iter) will be used as the second argument. For all subsequent iterations, The result from the previous application of the reducing-fcn will be used as the first argument to the reducing-fcn and the second argument will be the next item in the collection when the collection is empty reduce will return the amalgamated result.
Example:
(import iter)
(test::assert-true (= 15 (iter::reduce (iter::vec-iter [1 2 3 4 5]) 0 +)))
(test::assert-true (= 16 (iter::reduce (iter::vec-iter [1 2 3 4 5]) 1 +)))
(test::assert-true (= "one hoopy frood" (iter::reduce (iter::vec-iter ["one " "hoopy " "frood"]) "" str)))
iter::repeat-iter
Usage: (iter::repeat-iter i [SCRATCH] [SCRATCH] iter)
Iterator that wraps and returns a single object on each call.
Example:
(import iter)
(let (test-iter (repeat-iter 3))
(test::assert-equal 3 (test-iter))
(test::assert-equal 3 (test-iter))
(test::assert-equal 3 (test-iter))
(test::assert-equal 3 (test-iter))
(test::assert-equal 3 (test-iter))
(set! test-iter (repeat-iter "iter"))
(test::assert-equal "iter" (test-iter))
(test::assert-equal "iter" (test-iter))
(test::assert-equal "iter" (test-iter))
(test::assert-equal "iter" (test-iter))
(test::assert-equal "iter" (test-iter)))
iter::string-iter
Usage: (iter::string-iter s [SCRATCH] [SCRATCH] idx slen [SCRATCH] [SCRATCH] iter)
Iterator that wraps a string. Each element is the next character.
Example:
(import iter)
(let (test-string-iter (string-iter "123"))
(test::assert-equal \1 (test-string-iter))
(test::assert-equal \2 (test-string-iter))
(test::assert-equal \3 (test-string-iter))
(test::assert-equal :*iter-empty* (test-string-iter)))
iter::vec-iter
Usage: (iter::vec-iter v [SCRATCH] [SCRATCH] idx vlen [SCRATCH] [SCRATCH] iter)
Iterator that wraps a vector.
Example:
(import iter)
(let (test-vec-iter (vec-iter [1 2 3]))
(test::assert-equal 1 (test-vec-iter))
(test::assert-equal 2 (test-vec-iter))
(test::assert-equal 3 (test-vec-iter))
(test::assert-equal :*iter-empty* (test-vec-iter))
(set! test-vec-iter (vec-iter (vec)))
(test::assert-equal :*iter-empty* (test-vec-iter)))
iter::vec-iter-pair
Usage: (iter::vec-iter-pair v [SCRATCH] [SCRATCH] fidx bidx [SCRATCH] [SCRATCH] iter iter)
Return a pair of iterators, one forward and one reverse for a vector. The two iterators will not overlap (i.e. the forward and reverse will never produce the same items).
Example:
(import iter)
(let ([fwd-iter, rev-iter] (vec-iter-pair [1 2 3]))
(test::assert-equal 1 (fwd-iter))
(test::assert-equal 3 (rev-iter))
(test::assert-equal 2 (fwd-iter))
(test::assert-equal :*iter-empty* (rev-iter))
(test::assert-equal :*iter-empty* (fwd-iter)))
(let ([fwd-iter, rev-iter] (vec-iter-pair (vec)))
(test::assert-equal :*iter-empty* (fwd-iter))
(test::assert-equal :*iter-empty* (rev-iter)))
iter::vec-iter-rev
Usage: (iter::vec-iter-rev v [SCRATCH] [SCRATCH] idx [SCRATCH] [SCRATCH] iter)
Iterator produces a vector in reverse.
Example:
(import iter)
(let (test-vec-iter (vec-iter-rev [1 2 3]))
(test::assert-equal 3 (test-vec-iter))
(test::assert-equal 2 (test-vec-iter))
(test::assert-equal 1 (test-vec-iter))
(test::assert-equal :*iter-empty* (test-vec-iter))
(set! test-vec-iter (vec-iter-rev (vec)))
(test::assert-equal :*iter-empty* (test-vec-iter)))
math
List of symbols:
%, *, +, -, /, abs, rem, rem_euclid
%
Usage: (% int int)
Remainder from dividing (arg 1) by (arg 2).
Note: Remainder and Modulo are two similar mathematical operations,
called rem
and rem_euclid
in Rust.
This function uses rem
which is the same as the %
operator in C.
With rem
, the sign of the result is the same as the dividend (arg 1).
With rem_euclid
, the sign of the result is always positive.
Example:
(test::assert-equal 0 (% 50 10))
(test::assert-equal 5 (% 55 10))
(test::assert-equal 1 (% 1 2))
(test::assert-equal -1 (% -10 3))
(test::assert-equal 1 (% 10 -3))
(test::assert-equal -1 (% -10 -3))
(test::assert-error (%))
(test::assert-error (% 1))
(test::assert-error (% 1 2 3))
(test::assert-error (% 1 2.0))
*
Usage: (* number*)
Multiply a sequence of numbers. (*) will return 1.
Example:
(test::assert-equal 1 (*))
(test::assert-equal 5 (* 5))
(test::assert-equal 5 (* 1 5))
(test::assert-equal 5.0 (* 1.0 5))
(test::assert-equal 7.5 (* 1.5 5))
(test::assert-equal 7.5 (* 1.5 5.0))
(test::assert-equal 15 (* 3 5))
(test::assert-equal 8 (* 1 2 4))
(test::assert-equal 16 (* 2 2 4))
(test::assert-equal 16.0 (* 2 2.0 4))
(test::assert-equal 16.0 (* 2.0 2.0 4.0))
(test::assert-equal 54.9999999999999 (* 100 0.55))
(test::assert-error (* 1 2 4 "5"))
+
Usage: (+ number*)
Add a sequence of numbers. (+) will return 0.
Example:
(test::assert-equal 0 (+))
(test::assert-equal 5 (+ 5))
(test::assert-equal 10 (+ 5 5))
(test::assert-equal 6 (+ 1 5))
(test::assert-equal 6.5 (+ 1 5.5))
(test::assert-equal 7 (+ 1 2 4))
(test::assert-error (+ 1 2 4 "5"))
-
Usage: (- number+)
Subtract a sequence of numbers. Requires at least one number (negate if only one number).
Example:
(test::assert-error (- 5 "2"))
(test::assert-equal -5 (- 5))
(test::assert-equal -5.0 (- 5.0))
(test::assert-equal -4 (- 1 5))
(test::assert-equal -4.5 (- 1 5.5))
(test::assert-equal 4 (- 10 2 4))
(test::assert-equal 4.5 (- 10 2 3.5))
/
Usage: (/ number+)
Divide a sequence of numbers. Requires at least two numbers.
No Examples
abs
Usage: (abs arg)
Returns absolute value of arg.
Example:
(test::assert-equal 2 (abs 2))
(test::assert-equal 144 (abs -144))
(test::assert-equal 4.53 (abs -4.53))
(test::assert-equal 36028797018963967 (abs -36028797018963967))
rem
Usage: (rem int int)
Remainder from dividing (arg 1) by (arg 2).
Note: Remainder and Modulo are two similar mathematical operations,
called rem
and rem_euclid
in Rust.
This function uses rem
which is the same as the %
operator in C.
With rem
, the sign of the result is the same as the dividend (arg 1).
With rem_euclid
, the sign of the result is always positive.
Example:
(test::assert-equal 0 (rem 50 10))
(test::assert-equal 5 (rem 55 10))
(test::assert-equal 1 (rem 1 2))
(test::assert-equal -1 (rem -10 3))
(test::assert-equal 1 (rem 10 -3))
(test::assert-equal -1 (rem -10 -3))
(test::assert-error (rem))
(test::assert-error (rem 1))
(test::assert-error (rem 1 2 3))
(test::assert-error (rem 1 2.0))
rem_euclid
Usage: (rem_euclid int int)
Least Non-negative number that can be added to a multiple of the divisor (arg 2) to get the dividend (arg 1).
The result should always be 0 <= result < divisor (arg 2).
Note: Remainder and Modulo are two similar mathematical operations,
called rem
and rem_euclid
in Rust.
With rem
, the sign of the result is the same as the dividend (arg 1).
With rem_euclid
, the sign of the result is always positive.
Example:
(test::assert-equal 0 (rem_euclid 50 10))
(test::assert-equal 5 (rem_euclid 55 10))
(test::assert-equal 1 (rem_euclid 1 2))
(test::assert-equal 2 (rem_euclid -10 3))
(test::assert-equal 1 (rem_euclid 10 -3))
(test::assert-equal 2 (rem_euclid -10 -3))
(test::assert-error (rem_euclid))
(test::assert-error (rem_euclid 1))
(test::assert-error (rem_euclid 1 2 3))
(test::assert-error (rem_euclid 1 2.0))
namespace
List of symbols:
get-in-namespace, get-namespaces, import, ns, with-ns
get-in-namespace
Usage: (get-in-namespace 'SYMBOL)
Return a vector containing all the globals currently defined namespace SYMBOL.
No Examples
get-namespaces
Usage: (get-namespaces)
Return a vector containing all the namespaces currently defined globally.
No Examples
import
Usage: (import namespace [:as symbol])
Will import a namespace. Without an :as then all symbols in the namespace will become available in the current namespace as if local. With [:as symbol] then all namespace symbols become available with symbol:: prepended.
Example:
(ns testing)
(def x #t)
(test::assert-true x)
(ns ::)
(test::assert-true testing::x)
(import testing)
(test::assert-true x)
(import testing :as t)
(test::assert-true t::x)
ns
Usage: (ns SYMBOL)
Changes to namespace. This is "open-ended" change and is intended for use with the REPL prefer with-ns for scripts. The symbol "::" will return to the "root" namespace (i.e. no namespace prepended to globals). This will cause all globals defined to have namespace:: prepended. This will also clear any existing imports.
Example:
(ns testing)
(def x #t)
(test::assert-true x)
(ns ::)
(test::assert-true testing::x)
with-ns
Usage: (with-ns SYMBOL sexp+)
Create a namespace and compile sexp+ within it. Restore the previous namespace when scope ends. THe symbol "::" will return to the "root" namespace (i.e. no namespace prepended to globals). This will cause all globals defined to have namespace:: prepended. This will also clear any existing imports.
Example:
(with-ns test-with-ns
(def ttf (fn () '(1 2 3)))
(test::assert-equal '(1 2 3) (ttf))
(test::assert-equal '(1 2 3) (test-out::ttf)))
(test::assert-equal '(1 2 3) (test-out::ttf))
pair
List of symbols:
car
Usage: (car pair)
Return the car (first item) from a pair. If used on a proper list this will be the first element.
Example:
(def tst-pairs-two (list 'x 'y 'z))
(test::assert-equal 'x (car tst-pairs-two))
(test::assert-equal 10 (car '(10)))
(test::assert-equal 9 (car '(9 11 13)))
cdr
Usage: (cdr pair)
Return the cdr (second item) from a pair. If used on a proper list this will be the list minus the first element.
Example:
(def tst-pairs-three (list 'x 'y 'z))
(test::assert-equal '(y z) (cdr tst-pairs-three))
(test::assert-equal nil (cdr '(10)))
(test::assert-equal '(13) (cdr '(9 13)))
(test::assert-equal '(11 13) (cdr '(9 11 13)))
list
Usage: (list item0 item1 .. itemN)
Create a proper list from pairs with items 0 - N.
Example:
(test::assert-equal '(1 2 3) (list 1 2 3))
xar!
Usage: (xar! pair expression)
Destructive form that replaces the car (first item) in a pair with a new expression.
If used on a proper list will replace the first item. Can be used on nil to create a pair (expression . nil).
Example:
(def tst-pairs-three (list 'x 'y 'z))
(test::assert-equal '(x y z) tst-pairs-three)
(test::assert-equal '(s y z) (xar! tst-pairs-three 's))
(test::assert-equal '(s y z) tst-pairs-three)
(def tst-pairs-four (list 't))
(test::assert-equal '(y) (xar! tst-pairs-four 'y))
(test::assert-equal '(y) tst-pairs-four)
xdr!
Usage: (xdr! pair expression)
Destructive form that replaces the cdr (second item) in a pair with a new expression.
If used on a proper list will replace everything after the first item. Can be used on nil to create a pair (nil . expression).
Example:
(def tst-pairs-five (list 'a 'b 'c))
(test::assert-equal '(a b c) tst-pairs-five)
(test::assert-equal '(a y z) (xdr! tst-pairs-five '(y z)))
(test::assert-equal '(a y z) tst-pairs-five)
(def tst-pairs-six (list 'v))
(test::assert-equal (list 'v) tst-pairs-six)
(test::assert-equal '(v . v) (xdr! tst-pairs-six 'v))
(test::assert-equal '(v . v) tst-pairs-six)
random
List of symbols:
probool
Usage: (probool), (probool numerator denominator)
PRObability of a BOOLean.
If no arguments are given, returns #t 1/2 of the time, otherwise takes two integers, numerator and denominator, and returns #t numerator/denominator of the time. Throws an error if denominator is 0. If (>= (/ numerator denominator) 1) probool always returns true. If numerator is 0 probool always returns false.
Example:
(def val0 (probool))
(test::assert-true (or (= #t val0) (= nil val0)))
(def val1 (probool 17 42))
(test::assert-true (or (= #t val1) (= nil val1)))
(test::assert-true (probool 1 1))
(test::assert-false (probool 0 42))
(test::assert-error-msg (probool 0 0) :rand "Denominator can not be zero")
(test::assert-error-msg (probool 0 0 0) :rand "Expected zero or two positive ints")
random
Usage: (random), (random limit)
Returns non-negative number less than limit and of the same type as limit.
Example:
(def rand-int (random 100))
(test::assert-true (and (>= rand-int 0) (< rand-int 100)))
(def rand-float (random 1.0))
(test::assert-true (and (>= rand-float 0.0) (< rand-float 1.0)))
(test::assert-error-msg (random -1) :rand "Expected positive number")
(test::assert-error-msg (random 1 2) :rand "Expected positive number, float or int")
random-str
Usage: (random-str str-length [char-set])
Takes a positive integer, str-length, and one of :hex, :ascii, :alnum, or a string. Returns random string of provided str-length composed of second argument, :hex results in random hex string, :ascii results in random string of all printable ascii characters, :alnum results in random string of all alphanumeric characters, and providing a string results in a random string composed by sampling input.
Example:
(test::assert-error-msg (random-str) :rand "Expected two arguments, length and charset")
(test::assert-error-msg (random-str 10) :rand "Expected two arguments, length and charset")
(test::assert-error-msg (random-str -1 :hex) :rand "Expected positive length")
(test::assert-error-msg (random-str 10 1) :rand "Second argument must be keyword or string")
(test::assert-error-msg (random-str 1 :hexy) :rand "Unknown symbol :hexy")
(test::assert-equal 10 (len (random-str 10 :hex)))
(test::assert-true (str-contains (random-str 42 "⚙") "⚙"))
(test::assert-equal 19 (len (random-str 19 :ascii)))
(test::assert-equal 91 (len (random-str 91 :alnum)))
scripting
List of symbols:
run-script
Usage: (run-script path) -> [last form value]
Read and eval a file (from path- a string).
Example:
(def test-load::test-fn)
(with-temp-file (fn (tmp)
(let (tst-file (fopen tmp :create))
(defer (fclose tst-file))
(fprn tst-file "(with-ns test-load")
(fprn tst-file " (defn test-fn () '(1 2 3)))"))
(run-script tmp)
(test::assert-equal '(1 2 3) (test-load::test-fn))))
sequence
List of symbols:
butlast, first, last, rest, seq-for
butlast
Usage: (butlast obj [SCRATCH] [SCRATCH] new-link)
Produces the provided list minus the last element. Nil if the list is empty or one element.
Example:
(test::assert-equal '(1 2) (butlast '(1 2 3)))
(test::assert-equal [1 2] (butlast [1 2 3]))
(test::assert-equal nil (butlast '(1)))
(test::assert-equal [] (butlast [1]))
(test::assert-equal nil (butlast '()))
(test::assert-equal nil (butlast nil))
(test::assert-equal nil (butlast []))
first
Usage: (first obj)
Produces the first element of the provided list or vector. Nil if the list/vector is nil/empty. Note this is like car that works for lists and vectors.
Example:
(test::assert-equal 1 (first '(1 2 3)))
(test::assert-equal 1 (first [1 2 3]))
(test::assert-equal nil (first '()))
(test::assert-equal nil (first nil))
(test::assert-equal [] (first []))
last
Usage: (last obj [SCRATCH] [SCRATCH] last-list [SCRATCH] [SCRATCH] i)
Produces the last element in a list or vector. Nil if the list/vector is empty.
Example:
(test::assert-equal 3 (last '(1 2 3)))
(test::assert-equal 3 (last [1 2 3]))
(test::assert-equal nil (last '()))
(test::assert-equal nil (last nil))
(test::assert-equal nil (last []))
rest
Usage: (rest obj)
Produces the provided list or vector minus the first element. Nil if the list/vector is nil/empty or one element. Note this is like cdr that works for lists and vectors. This calls vec-slice to create a new vector when called with a vector (i.e. is much more efficient with lists).
Example:
(test::assert-equal '(2 3) (rest '(1 2 3)))
(test::assert-equal [2 3] (rest [1 2 3]))
(test::assert-equal nil (rest '(1)))
(test::assert-equal [] (rest [1]))
(test::assert-equal nil (rest '()))
(test::assert-equal nil (rest nil))
(test::assert-equal [] (rest []))
seq-for
Usage: (seq-for bind in items body [SCRATCH] [SCRATCH] lst)
Loops over each element in a sequence. Simple version that works with lists and vectors, use iterator::for in general.
Example:
(def i 0)
(seq-for x in '(1 2 3 4 5 6) (set! i (+ 1 i)))
(test::assert-equal 6 i)
shell
List of symbols:
args, shell-exe, bg-color-rgb, fg-color-rgb, syntax-off, syntax-on, sys-command?
args
Usage: args
A vector of the argumants passed to the script. The first argument will be the name of the script.
No Examples
shell-exe
Usage: shell-exe
A string that contains the executable that is running the script.
No Examples
bg-color-rgb
Usage: (bg-color-rgb red-val green-val blue-val)
Set the background color to the desired rgb where each arg is an integer between 0 and 255 inclusive.
Example:
(test::assert-equal "\x1b[48;2;128;128;128m" (bg-color-rgb 128 128 128))
(test::assert-equal "\x1b[48;2;255;255;255m" (bg-color-rgb 255 255 255))
(test::assert-equal "\x1b[48;2;255;0;0m" (bg-color-rgb 255 0 0))
(test::assert-equal "\x1b[48;2;0;255;0m" (bg-color-rgb 0 255 0))
(test::assert-equal "\x1b[48;2;0;0;255m" (bg-color-rgb 0 0 255))
(test::assert-equal "\x1b[48;2;0;0;0m" (bg-color-rgb 0 0 0))
fg-color-rgb
Usage: (fg-color-rgb red-val green-val blue-val)
Set the foreground color to the desired rgb where each arg is an integer between 0 and 255 inclusive.
Example:
(test::assert-equal "\x1b[38;2;0;0;0m" (fg-color-rgb 0 0 0))
(test::assert-equal "\x1b[38;2;128;128;128m" (fg-color-rgb 128 128 128))
(test::assert-equal "\x1b[38;2;255;0;0m" (fg-color-rgb 255 0 0))
(test::assert-equal "\x1b[38;2;0;255;0m" (fg-color-rgb 0 255 0))
(test::assert-equal "\x1b[38;2;0;0;255m" (fg-color-rgb 0 0 255))
(test::assert-equal "\x1b[38;2;255;255;255m" (fg-color-rgb 255 255 255))
syntax-off
Usage: (syntax-off)
Turn off syntax highlighting at the repl.
No Examples
syntax-on
Usage: (syntax-on [SCRATCH] [SCRATCH] plev ch sys-syms token in-sys-command tok-command is-lisp paren-color my-sys-command? sys-command-color command-color prrawtoken prtoken paren-open paren-close whitespace in-quote out last-ch str-mapper-fn line-handler)
Turn on syntax highlighting at the repl.
No Examples
sys-command?
Usage: (sys-command? com)
True if the supplied command is a system command.
Example:
(test::assert-true (sys-command? "ls"))
(test::assert-false (sys-command? "rst-not-a-command-strsnt"))
string
List of symbols:
str, str-bytes, str-cat-list, str-contains, str-empty?, str-lower, str-map, str-push!, str-replace, str-split, str-splitn, str-starts-with, str-sub, str-trim, str-trim!, str-upper
str
Usage: (str arg0 ... argN) -> string
Make a new string with its arguments.
Arguments will be turned into strings. If an argument is a process then the output of the process will be captured and put into the string.
Example:
(test::assert-equal "stringsome" (str "string" "some"))
(test::assert-equal "string" (str "string" ""))
(test::assert-equal "string 50" (str "string" " " 50))
str-bytes
Usage: (str-bytes string) -> int
Return number of bytes in a string (may be more then length).
Strings are utf8 so it chars and bytes may not be a one to one match.
Example:
(test::assert-equal 4 (str-bytes "Stau"))
(test::assert-equal 0 (str-bytes ""))
; Note 5 chars and 6 bytes because of the final char.
(test::assert-equal 6 (str-bytes "StauΣ"))
str-cat-list
Usage: (str-cat-list join-str sequence) -> string
Build a string by concatenating a sequence of strings by join-str.
Example:
(test::assert-equal "stringxxxyyyxxxsome" (str-cat-list "xxx" ["string" "yyy" "some"]))
(test::assert-equal "string yyy some" (str-cat-list " " ["string" "yyy" "some"]))
(test::assert-equal "stringyyysome" (str-cat-list "" ["string" "yyy" "some"]))
str-contains
Usage: (str-contains string pattern) -> #t/#f
True if string contains pattern (pattern will be converted to a string first).
Example:
(test::assert-true (str-contains "Stausomething" "Stau"))
(test::assert-false (str-contains "Stausomething" "StaU"))
(test::assert-true (str-contains "Stausomething" "some"))
(test::assert-false (str-contains "Stausomething" "Some"))
(test::assert-true (str-contains "Stausomething" "thing"))
(test::assert-false (str-contains "Stausomething" "Thing"))
(test::assert-true (str-contains "StausomeΣthing" "someΣ"))
str-empty?
Usage: (str-empty? string) -> #t/#f
Is a string empty? Let's find out...
Example:
(test::assert-true (str-empty? ""))
(test::assert-true (str-empty? (str-trim " ")))
(test::assert-false (str-empty? " "))
(test::assert-false (str-empty? "string"))
str-lower
Usage: (str-lower string) -> string
Get all lower case string from a string.
Example:
(test::assert-equal "stau" (str-lower "STAU"))
(test::assert-equal "stau" (str-lower "stau"))
(test::assert-equal "stau" (str-lower "Stau"))
(test::assert-equal "stau" (str-lower "StaU"))
(test::assert-equal "stau" (str-lower "sTaU"))
str-map
Usage: (str-map string lambda) -> string
Make a new string by applying lambda to each char in input string.
Example:
(test::assert-equal "XstringXstrX" (str-map "xstringxstrx" (fn (ch) (if (= "x" ch) "X" ch))))
(def test-str-map (str-map "xstringxstrx" (fn (ch) (if (= "x" ch) "X" ch))))
(test::assert-equal "XstringXstrX" test-str-map)
(test::assert-true (string? test-str-map))
(def test-str-map (str-map (str "xstringxstrx") (fn (ch) (if (= "x" ch) "X" ch))))
(test::assert-equal "XstringXstrX" test-str-map)
(test::assert-true (string? test-str-map))
str-push!
Usage: (str-push! string arg0 ... argN) -> string
Push the args (as strings) onto the string. This is a destructive form.
Arguments will be turned into strings. Returns the string it was given.
Example:
(test::assert-equal "stringsome" (str-push! (str "string") "some"))
(def test-str-push (str "def-string"))
(test::assert-equal "def-stringsome" (str-push! test-str-push "some"))
(test::assert-equal "def-stringsome" test-str-push)
str-replace
Usage: (str-replace string old-pattern new-pattern) -> string
Replace occurrences of second string with third in the first string.
Example:
(test::assert-equal "some yyy string" (str-replace "some xxx string" "xxx" "yyy"))
(test::assert-equal "some yyy string yyy" (str-replace "some xxx string xxx" "xxx" "yyy"))
(test::assert-equal "yyy some yyy string yyy" (str-replace "xxx some xxx string xxx" "xxx" "yyy"))
str-split
Usage: (str-split string split-pattern) -> vector
Use a pattern to split a string (:whitespace to split on whitespace).
Example:
(test::assert-equal ["some" "yyy" "string"] (str-split "somexxxyyyxxxstring" "xxx"))
(test::assert-equal ["some" "yyy" "string" ""] (str-split "somexxxyyyxxxstringxxx" "xxx"))
(test::assert-equal ["" "some" "yyy" "string" ""] (str-split "xxxsomexxxyyyxxxstringxxx" "xxx"))
(test::assert-equal ["some" "yyy" "string"] (str-split "some yyy string" :whitespace))
(test::assert-equal ["somexxxyyyxxxstring"] (str-split "somexxxyyyxxxstring" :whitespace))
(test::assert-equal ["somexxxyyyxxxstring"] (str-split "somexxxyyyxxxstring" "zzz"))
str-splitn
Usage: (str-splitn n split-pattern string) -> vector
Use a pattern to split a string with at most n items.
Example:
(test::assert-equal ["some" "yyy" "string"] (str-splitn 3 "xxx" "somexxxyyyxxxstring"))
(test::assert-equal ["some" "yyy" "string"] (str-splitn 4 "xxx" "somexxxyyyxxxstring"))
(test::assert-equal ["some" "yyy" "stringxxxother"] (str-splitn 3 "xxx" "somexxxyyyxxxstringxxxother"))
(test::assert-equal ["somexxxyyyxxxstringxxxother"] (str-splitn 1 "xxx" "somexxxyyyxxxstringxxxother"))
(test::assert-equal [] (str-splitn 0 "xxx" "somexxxyyyxxxstringxxxzero"))
str-starts-with
Usage: (str-starts-with string pattern) -> #t/#f
True if string start with pattern.
Example:
(test::assert-true (str-starts-with "Stausomething" "Stau"))
(test::assert-false (str-starts-with "Stausomething" "StaU"))
str-sub
Usage: (str-sub string start [length]) -> string
Return a substring from a string given start (0 based) and optional length. If length is 0 or not provided produces the rest of the string from start to string end.
Example:
(test::assert-equal "string" (str-sub "stringxxxyyyxxxsome" 0 6))
(test::assert-equal "some" (str-sub "stringxxxyyyxxxsome" 15 4))
(test::assert-equal "yyy" (str-sub "stringxxxyyyxxxsome" 9 3))
(test::assert-equal "some" (str-sub "stringxxxyyyxxxsome" 15))
str-trim
Usage: (str-trim string [:right | :left]) -> string
Trim right and/or left whitespace from string. With no optional keywork trims both, otherwise :right or :left specify right or left trimming.
Example:
(test::assert-equal "some string" (str-trim " some string"))
(test::assert-equal "some string" (str-trim " some string "))
(test::assert-equal "some string" (str-trim (str " some string ")))
(test::assert-equal "some string" (str-trim "some string "))
(test::assert-equal "some string" (str-trim "some string"))
(test::assert-equal " some string" (str-trim " some string" :right))
(test::assert-equal " some string" (str-trim " some string " :right))
(test::assert-equal " some string" (str-trim (str " some string ") :right))
(test::assert-equal "some string" (str-trim "some string " :right))
(test::assert-equal "some string" (str-trim "some string" :right))
(test::assert-equal "some string" (str-trim " some string" :left))
(test::assert-equal "some string " (str-trim " some string " :left))
(test::assert-equal "some string " (str-trim (str " some string ") :left))
(test::assert-equal "some string " (str-trim "some string " :left))
(test::assert-equal "some string" (str-trim "some string" :left))
str-trim!
Usage: (str-trim! string [:right | :left]) -> string
Trim right and/or left whitespace from string in place. With no optional keywork trims both, otherwise :right or :left specify right or left trimming.
This is a destructive operation (unlike str-trim) and requires an actual non-const string as it's first argument. It returns this string on success.
Example:
(test::assert-equal "some string" (str-trim! (str " some string")))
(test::assert-equal "some string" (str-trim! (str " some string ")))
(test::assert-equal "some string" (str-trim! (str (str " some string "))))
(test::assert-equal "some string" (str-trim! (str "some string ")))
(test::assert-equal "some string" (str-trim! (str "some string")))
(test::assert-equal " some string" (str-trim! (str " some string") :right))
(test::assert-equal " some string" (str-trim! (str " some string ") :right))
(test::assert-equal " some string" (str-trim! (str (str " some string ")) :right))
(test::assert-equal "some string" (str-trim! (str "some string ") :right))
(test::assert-equal "some string" (str-trim! (str "some string") :right))
(test::assert-equal "some string" (str-trim! (str " some string") :left))
(test::assert-equal "some string " (str-trim! (str " some string ") :left))
(test::assert-equal "some string " (str-trim! (str (str " some string ")) :left))
(test::assert-equal "some string " (str-trim! (str "some string ") :left))
(test::assert-equal "some string" (str-trim! (str "some string") :left))
str-upper
Usage: (str-upper string) -> string
Get all upper case string from a string.
Example:
(test::assert-equal "STAU" (str-upper "STAU"))
(test::assert-equal "STAU" (str-upper "stau"))
(test::assert-equal "STAU" (str-upper "Stau"))
(test::assert-equal "STAU" (str-upper "StaU"))
(test::assert-equal "STAU" (str-upper "sTaU"))
system
List of symbols:
sleep
Usage: (sleep milliseconds) -> nil
Sleep for at least the provided milliseconds (must be a positive integer), otherwise function will no-op.
No Examples
test
List of symbols:
test::assert-equal, test::assert-error, test::assert-error-msg, test::assert-false, test::assert-not-equal, test::assert-true, test::assert-equal, test::assert-error, test::assert-error-msg, test::assert-false, test::assert-not-equal, test::assert-true
test::assert-equal
Usage: (test::assert-equal expected-val right-val body)
Asserts the two values are identical.
No Examples
test::assert-error
Usage: (test::assert-error val body)
Asserts the value is an error
No Examples
test::assert-error-msg
Usage: (test::assert-error-msg form key msg)
Test asserts an error is thrown with a given key and message.
Example:
(test::assert-error-msg (err "error thrown") :error "error thrown")
test::assert-false
Usage: (test::assert-false val body)
Asserts the value is false
No Examples
test::assert-not-equal
Usage: (test::assert-not-equal expected-val right-val body)
Asserts the two values are not identical.
No Examples
test::assert-true
Usage: (test::assert-true val body)
Asserts the value is true.
No Examples
test::assert-equal
Usage: (test::assert-equal expected-val right-val body)
Asserts the two values are identical.
No Examples
test::assert-error
Usage: (test::assert-error val body)
Asserts the value is an error
No Examples
test::assert-error-msg
Usage: (test::assert-error-msg form key msg)
Test asserts an error is thrown with a given key and message.
Example:
(test::assert-error-msg (err "error thrown") :error "error thrown")
test::assert-false
Usage: (test::assert-false val body)
Asserts the value is false
No Examples
test::assert-not-equal
Usage: (test::assert-not-equal expected-val right-val body)
Asserts the two values are not identical.
No Examples
test::assert-true
Usage: (test::assert-true val body)
Asserts the value is true.
No Examples
type
List of symbols:
->float, ->int, callable?, char?, err?, io?, list?, nil?, ok?, pair?, seq?, string?, symbol?, vec?
->float
Usage: (->float ?float) -> float
If string or other value is a valid representation of a float return that float. Error if not.
Example:
(test::assert-equal 0.0 (->float "0"))
(test::assert-equal 11.0 (->float 11))
(test::assert-equal 10.0 (->float "10.0"))
(test::assert-equal 13.0 (->float :13))
(test::assert-equal 10.5 (->float "10.5"))
(test::assert-equal 101.0 (->float "101"))
(test::assert-equal -101.95 (->float "-101.95"))
(test::assert-error (->float "not int"))
(test::assert-error (->float "--10"))
;; for some reason this ->sym test case must be last or else there's an error w/ load
(test::assert-equal 12.0 (->float (->sym 12)))
->int
Usage: (->int ?int) -> int
If string or other value is a valid representation of an integer return that int. Error if not.
Note, if value is a float (or is a string that casts initially to a float) and it is NaN, +/- infinity, < i56::MIN, or > i56::MAX the function will error.
Example:
(test::assert-equal 0 (->int "0"))
(test::assert-equal 101 (->int "101"))
(test::assert-equal 1101 (->int :1101))
(test::assert-equal 8 (->int 8.1))
(test::assert-equal -111 (->int "-111"))
(test::assert-equal 10 (->int "10.0"))
(test::assert-error (->int "not int"))
(test::assert-error (->int "--10"))
;; for some reason this ->sym test case must be last or else there's an error w/ load
(test::assert-equal 1102 (->int (->sym 1102)))
callable?
Usage: (callable? v [SCRATCH] [SCRATCH] t)
Usage: (callable? to-test)
No Examples
char?
Usage: (char? expression)
True if the expression is a char, false otherwise.
Example:
(test::assert-true (char? \a))
(test::assert-false (char? 1))
(test::assert-false (char? "a"))
err?
Usage: (err? expression)
True if the expression is an error, false otherwise.
Example:
(test::assert-true (err? (mk-err :arr "test")))
(test::assert-false (err? nil))
io?
Usage: (io? expression)
True if the expression is an IO object (file), false otherwise.
Example:
(def iotst (fopen "/tmp/iotst" :create))
(test::assert-true (io? iotst))
(test::assert-false (io? 1))
(test::assert-false (io? '(1 2 3)))
(test::assert-false (io? (list)))
list?
Usage: (list? expression)
True if the expression is a list, false otherwise.
Example:
(test::assert-true (list? '(1 2 3)) "reader macro")
(test::assert-true (list? (list 1 2 3)) "list")
(test::assert-false (list? 1))
(test::assert-false (list? [1 2 3]))
(test::assert-false (list? []))
(test::assert-false (list? '(1 . 2)))
nil?
Usage: (nil? v)
True if the expression is nil, false otherwise
Example:
(test::assert-true (nil? ()))
(test::assert-true (nil? '()))
(test::assert-true (nil? nil))
(test::assert-true (nil? (list)))
(test::assert-false (nil? #f))
ok?
Usage: (ok? expression)
True if the expression is NOT an error, false if it is an error.
Example:
(test::assert-false (ok? (mk-err :arr "test")))
(test::assert-true (ok? nil))
pair?
Usage: (pair? expression)
True if the expression is a pair, false otherwise.
Example:
(test::assert-true (pair? '(1 . 2)) "reader macro")
(test::assert-true (pair? (cons 1 2)) "cons")
(test::assert-true (pair? '(1 2)))
(test::assert-false (pair? 1))
(test::assert-false (pair? [1 2 3]))
(test::assert-false (pair? (vec)))
seq?
Usage: (seq? expression)
True if expression is a list or vector, false otherwise.
Example:
(test::assert-true (seq? '(1 2 3)))
(test::assert-true (seq? [1 2 3]))
(test::assert-true (seq? []))
(test::assert-false (seq? "aaa"))
(test::assert-false (seq? 1))
string?
Usage: (string? expression)
True if the expression is a string, false otherwise.
Example:
(test::assert-true (string? "string"))
(test::assert-false (string? 1))
symbol?
Usage: (symbol? expression)
True if the expression is a symbol, false otherwise.
Example:
(test::assert-true (symbol? 'symbol))
(test::assert-false (symbol? 1))
vec?
Usage: (vec? expression)
True if the expression is a vector, false otherwise.
Example:
(test::assert-true (vec? [1 2 3]) "reader macro")
(test::assert-true (vec? (make-vec)) "make-vec")
(test::assert-true (vec? (vec 1 2 3)) "vec")
(test::assert-false (vec? 1))
(test::assert-false (vec? '(1 2 3)))
(test::assert-false (vec? (list)))
vector
List of symbols:
make-vec, vec, vec->list, vec-pop!, vec-push!, vec-slice
make-vec
Usage: (make-vec capacity default)
Make a new vector with capacity and default item(s).
Example:
(test::assert-equal [] (make-vec))
(test::assert-equal ['x 'x 'x] (make-vec 3 'x))
(test::assert-equal [nil nil nil nil nil] (make-vec 5 nil))
(test::assert-equal [] (make-vec 5))
vec
Usage: (vec item1 item2 .. itemN)
Make a new vector with items.
Example:
(test::assert-equal [] (vec))
(test::assert-equal [1 2 3] (vec 1 2 3))
vec->list
Usage: (vec->list vector)
Convert a vector to a list.
No Examples
vec-pop!
Usage: (vec-pop! vector) -> object
Pops the last object off of the end of the vector. This is destructive!
Example:
(def test-pop-vec (vec 1 2 3))
(test::assert-equal 3 (vec-pop! test-pop-vec))
(test::assert-equal [1 2] test-pop-vec)
(test::assert-equal 2 (vec-pop! test-pop-vec))
(test::assert-equal [1] test-pop-vec)
(test::assert-equal 1 (vec-pop! test-pop-vec))
(test::assert-equal [] test-pop-vec)
vec-push!
Usage: (vec-push! vector object) -> vector
Pushes the provided object onto the end of the vector. This is destructive!
Example:
(def test-push-vec (vec))
(test::assert-equal [1] (vec-push! test-push-vec 1))
(test::assert-equal [1] test-push-vec)
(test::assert-equal [1 2] (vec-push! test-push-vec 2))
(test::assert-equal [1 2] test-push-vec)
(test::assert-equal [1 2 3] (vec-push! test-push-vec 3))
(test::assert-equal [1 2 3] test-push-vec)
vec-slice
Usage: (vec-slice vector start end)
Returns a slice of a vector (0 based indexes, end is exclusive).
Example:
(test::assert-equal [5 6] (vec-slice [1 2 3 4 5 6] 4 6))
(test::assert-equal [1 2 3] (vec-slice [1 2 3 4 5 6] 0 3))
(test::assert-equal [3 4 5] (vec-slice [1 2 3 4 5 6] 2 5))
(test::assert-equal [3 4 5 6] (vec-slice [1 2 3 4 5 6] 2))
User Forms
When built locally (see doc/README.md) the mdbook generator has access to the user's
slosh environment. This enables creating documentation in md form of all user defined
functions. The user's init.slosh is automatically loaded, so any additional files it
loads are also imported. If the user needs to alter the slosh load path or add
additional files to be loaded (presumably because they aren't imported in init.slosh
or any slosh file it imports) it can be done by adding the paths in the user-doc-files
and user-doc-load-paths
string arrays in doc/book.toml. The default is to use
~/.config/slosh/
as the load path and ~/.config/slosh/init.slosh
for the rc file.
List of sections:
tracking function Parity Between sl-sh and slosh
Forms yet to be implemented: 321
Forms implemented or skipped: 200
? | Slosh Form | Notes |
---|---|---|
✅ | % | |
✅ | * | |
✅ | *active-ns* | Renamed to: *ns* |
✅ | *bg-black* | |
✅ | *bg-blue* | |
✅ | *bg-cyan* | |
✅ | *bg-default* | |
✅ | *bg-green* | |
✅ | *bg-magenta* | |
✅ | *bg-red* | |
✅ | *bg-white* | |
✅ | *bg-yellow* | |
☑️ | *collection-src* | Not necessary in slosh. |
☑️ | *core-src* | Not necessary in slosh. |
✅ | *euid* | |
❌ | *euler* | |
✅ | *fg-black* | |
✅ | *fg-blue* | |
✅ | *fg-cyan* | |
✅ | *fg-default* | |
✅ | *fg-green* | |
✅ | *fg-magenta* | |
✅ | *fg-red* | |
✅ | *fg-white* | |
✅ | *fg-yellow* | |
☑️ | *getopts-log* | Not necessary in slosh. |
☑️ | *getopts-src* | Not necessary in slosh. |
☑️ | *iterator-src* | Not necessary in slosh. |
❌ | *last-command* | |
✅ | *last-status* | |
❌ | *lib-src* | |
❌ | *load-path* | |
✅ | *ns* | |
❌ | *ns-exports* | |
❌ | *pi* | |
❌ | *read-table* | |
❌ | *read-table-terminal* | |
❌ | *repl-settings* | |
❌ | *run-script* | |
☑️ | *seq-src* | Not necessary in slosh. |
☑️ | *shell-read-src* | Not necessary in slosh. |
☑️ | *shell-src* | Not necessary in slosh. |
☑️ | *slsh-std-src* | Not necessary in slosh. |
☑️ | *slshrc-src* | Not necessary in slosh. |
❌ | *std-lib-exported-syms-hash* | |
❌ | *std-lib-namespaces* | |
❌ | *std-lib-syms-hash* | |
❌ | *stderr* | |
❌ | *stdin* | |
❌ | *stdout* | |
❌ | *string-read-table* | |
☑️ | *struct-src* | Not necessary in slosh. |
☑️ | *test-src* | Not necessary in slosh. |
✅ | *uid* | |
❌ | =+ | |
✅ | - | |
❌ | -> | |
❌ | ->> | |
✅ | / | |
❌ | 2pow | |
✅ | < | |
✅ | <= | |
✅ | = | |
✅ | > | |
✅ | >= | |
❌ | ^ns-stack-xyz^ | |
❌ | __prompt | |
✅ | abs | |
❌ | alias | |
❌ | alias? | |
✅ | and | |
❌ | and-let* | |
❌ | append | |
❌ | append-iter | |
❌ | append-to! | |
✅ | apply | |
❌ | apply-defaults | |
❌ | arccos | |
❌ | arcsin | |
❌ | arctan | |
✅ | args | Renamed to: *args* |
❌ | arity-zero-can-not-be-required | |
❌ | assert-equal | |
❌ | assert-error | |
❌ | assert-error-msg | |
❌ | assert-false | |
❌ | assert-includes | |
❌ | assert-not-equal | |
❌ | assert-not-includes | |
❌ | assert-true | |
✅ | back-quote | |
❌ | bg | |
✅ | bg-color-rgb | |
✅ | block | |
❌ | boolean? | |
❌ | builtin? | |
✅ | butlast | |
❌ | caaar | |
❌ | caadr | |
❌ | caar | |
❌ | cadar | |
❌ | cadddr | |
❌ | caddr | |
❌ | cadr | |
✅ | callable? | |
✅ | car | |
✅ | cd | |
❌ | cdaar | |
❌ | cdadr | |
❌ | cdar | |
❌ | cddar | |
❌ | cdddr | |
❌ | cddr | |
✅ | cdr | |
❌ | ceil | |
❌ | chain | |
❌ | chain-and | |
❌ | chain-when | |
❌ | char->int | |
✅ | char-lower | |
✅ | char-upper | |
✅ | char-whitespace? | |
✅ | char? | |
❌ | check | |
❌ | check-custom | |
❌ | clear-dirs | |
❌ | close | |
❌ | codepoints | |
❌ | collate-fs-changes | |
❌ | collect | |
❌ | collect-copy | |
❌ | collect-str | |
❌ | collect-vec | |
✅ | cond | |
❌ | consume-comment | |
❌ | consume-whitespace | |
❌ | cos | |
✅ | dec! | |
✅ | def | |
✅ | def? | |
✅ | defmacro | |
✅ | defn | |
☑️ | defstruct | Will consider other implementations if struct-like functionality if desired. |
☑️ | deftrait | Will consider other implementations if trait-like functionality is desired. |
❌ | dirs | |
✅ | do | |
❌ | do-unstr | |
✅ | doc | |
☑️ | doc-raw | Possible now with command: (get-prop 'symbol :doc-string) |
✅ | dotimes | |
✅ | dotimes-i | |
☑️ | double-ended-iter? | Not necessary in slosh. |
☑️ | double-ended-iterator | Not necessary in slosh. |
✅ | dyn | |
❌ | empty-seq? | |
✅ | empty? | |
❌ | enforce-constrains | |
❌ | epoch | |
✅ | eprint | Renamed to: epr |
✅ | eprintln | Renamed to: eprn |
✅ | err | |
❌ | err> | |
❌ | err>> | |
❌ | err>null | |
❌ | error-stack-off | |
❌ | error-stack-on | |
✅ | eval | |
✅ | exit | |
❌ | exp | |
❌ | expand-brace | |
❌ | expand-dollar | |
✅ | expand-macro | |
❌ | expand-macro-all | |
❌ | expand-macro1 | |
❌ | expand-tilde | |
❌ | export | |
❌ | false? | |
❌ | falsey? | |
❌ | fc | |
❌ | fg | |
✅ | fg-color-rgb | |
❌ | file-iter | |
❌ | file? | |
❌ | filter | |
❌ | filter-iter | |
❌ | find-symbol | |
✅ | first | |
❌ | first-quartile | |
❌ | fix-one-arg-bindings | |
❌ | flatten-args | |
❌ | float->int | |
❌ | float? | |
❌ | floor | |
✅ | flush | Renamed to: fflush |
✅ | fn | |
❌ | fn-to-predicate | |
❌ | fncall | |
❌ | for | |
❌ | for-i | |
❌ | fork | |
❌ | format | |
❌ | fract | |
✅ | fs-accessed | |
✅ | fs-base | |
✅ | fs-crawl | |
✅ | fs-dir? | |
✅ | fs-exists? | |
✅ | fs-file? | |
✅ | fs-len | |
✅ | fs-modified | |
❌ | fs-notify | |
✅ | fs-parent | |
✅ | fs-rm | |
✅ | fs-same? | |
❌ | func? | |
✅ | gensym | |
❌ | get-arity | |
❌ | get-dirs | |
❌ | get-env | |
✅ | get-error | |
❌ | get-home | |
❌ | get-next-params | |
❌ | get-pid | |
✅ | get-rgb-seq | |
✅ | get-temp | |
✅ | get-temp-file | |
❌ | get_pwd | |
❌ | getopts | |
❌ | getopts-bad-first-arg | |
❌ | getopts-bad-option-arity | |
❌ | getopts-help | |
❌ | getopts-help--options-map-is-map | |
❌ | getopts-illegal-option | |
❌ | getopts-invalid-type-function | |
❌ | getopts-options-map-is-map | |
❌ | getopts-type-error-message | |
✅ | glob | |
❌ | handle-last-command | |
❌ | handle-process | |
❌ | hash-clear! | |
❌ | hash-get | |
❌ | hash-haskey | |
✅ | hash-keys | |
✅ | hash-remove! | |
❌ | hash-set! | |
❌ | hash? | |
❌ | history-context | |
❌ | history-empty? | |
❌ | history-length | |
❌ | history-nth | |
❌ | history-push | |
❌ | history-push-throwaway | |
✅ | identity | |
✅ | if | |
✅ | import | |
✅ | in? | |
✅ | inc! | |
❌ | int->float | |
❌ | int? | |
❌ | interleave | |
❌ | interleave-iter | |
❌ | intern-stats | |
❌ | is-getopts-option-string | |
❌ | is-multi-char-arg | |
❌ | is-multi-single-char-args | |
❌ | is-single-char-arg | |
❌ | iter | |
❌ | iter-or-single | |
❌ | iter? | |
❌ | iterator | |
❌ | jobs | |
❌ | join | |
❌ | lambda? | |
✅ | last | |
❌ | len0? | |
❌ | len>0? | |
❌ | length | |
✅ | let | |
✅ | let* | Renamed to: let |
❌ | let-env | |
✅ | list | |
❌ | list-iter | |
❌ | list-vec? | |
✅ | list? | |
❌ | lists= | |
❌ | lne | |
✅ | load | |
❌ | log | |
❌ | log2 | |
❌ | logger | |
✅ | loop | |
✅ | macro | |
❌ | macro? | |
✅ | make-hash | |
❌ | make-hash-with-keys | |
❌ | make-regex | |
✅ | make-vec | |
❌ | map | |
❌ | map-iter | |
✅ | match | |
❌ | max | |
❌ | maybe-docstring? | |
❌ | maybe-glob? | |
❌ | mean | |
❌ | median | |
❌ | meld | |
❌ | meld-iter | |
❌ | meta-add-tags | |
❌ | meta-column-no | |
❌ | meta-file-name | |
❌ | meta-line-no | |
❌ | meta-tag? | |
❌ | method | |
❌ | min | |
❌ | mkli | |
❌ | mode | |
❌ | next! | |
✅ | nil? | |
❌ | non-empty-seq? | |
❌ | none? | |
✅ | not | |
❌ | ns-auto-export | |
✅ | ns-create | Renamed to: with-ns |
✅ | ns-enter | Renamed to: ns |
❌ | ns-exists? | |
☑️ | ns-export | Everything in slosh is exported by default. |
✅ | ns-import | Renamed to: import |
✅ | ns-list | Renamed to: get-namespaces |
☑️ | ns-pop | Not necessary in slosh. |
☑️ | ns-push | Not necessary in slosh. |
✅ | ns-symbols | Renamed to: get-in-namespace |
✅ | nsubstitute! | |
❌ | nth | |
❌ | null | |
❌ | nyi | |
✅ | occurs | |
✅ | open | Renamed to: fopen |
✅ | or | |
❌ | out-err> | |
❌ | out-err>> | |
❌ | out-err>null | |
❌ | out> | |
❌ | out>> | |
❌ | out>null | |
☑️ | pair= | Do not need separate equals specifier for pair. |
✅ | pair? | |
❌ | path_list_trunc | |
❌ | pid | |
❌ | pipe | |
☑️ | pipe-err | Not necessary in slosh. |
❌ | popd | |
❌ | pow | |
✅ | print | Renamed to: pr |
☑️ | print-error | Now one drops in to the debugger when an error occurs. |
✅ | println | Renamed to: prn |
✅ | probool | |
❌ | process? | |
❌ | prompt | |
❌ | pushd | |
❌ | qsort | |
✅ | quote | |
✅ | random | |
✅ | random-str | |
❌ | range | |
❌ | range-iter | |
❌ | re-color | |
❌ | re-find | |
❌ | re-find-all | |
❌ | re-match | |
❌ | re-replace | |
✅ | read | |
✅ | read-all | |
✅ | read-line | |
❌ | read-list | |
❌ | read-string | |
❌ | read-var | |
❌ | read-var-bracket | |
❌ | reader-macro-dot | |
❌ | reap-jobs | |
✅ | recur | |
❌ | redir&> | |
❌ | redir&>> | |
❌ | redir2> | |
❌ | redir2>> | |
❌ | redir> | |
❌ | redir>> | |
❌ | reduce | |
❌ | reduce-times | |
✅ | ref | |
❌ | regex? | |
❌ | register-alias | |
❌ | repeat | |
❌ | repeat-iter | |
❌ | repl | |
❌ | repl-eof | |
❌ | repl-line | |
❌ | required-argument | |
✅ | rest | |
❌ | return-from | |
✅ | reverse | |
❌ | reverse-iter | |
❌ | rm-esc | |
❌ | round | |
❌ | run-bg-first | |
❌ | run-bg-prep-args | |
❌ | run-example | |
❌ | run-ns-example | |
✅ | seq-for | |
✅ | seq? | |
✅ | set! | |
❌ | set-dirs-max | |
❌ | set_prompt_tail | |
❌ | setnth! | |
❌ | setup-chainer | |
❌ | shell-read | |
❌ | shell-read-int | |
❌ | sin | |
❌ | single-iter | |
✅ | sleep | |
❌ | slice | |
❌ | slice-iter | |
❌ | some? | |
❌ | sqrt | |
❌ | std-dev | |
✅ | str | |
❌ | str->float | |
❌ | str->int | |
❌ | str-append | |
✅ | str-bytes | |
✅ | str-cat-list | |
❌ | str-clear! | |
✅ | str-contains | |
✅ | str-empty? | |
❌ | str-iter-empty? | |
❌ | str-iter-next! | |
❌ | str-iter-peek | |
❌ | str-iter-start | |
✅ | str-lower | |
❌ | str-ltrim | |
✅ | str-map | |
❌ | str-nth | |
✅ | str-push! | |
✅ | str-replace | |
❌ | str-rsplit | |
❌ | str-rsplitn | |
❌ | str-rtrim | |
✅ | str-split | |
✅ | str-splitn | |
✅ | str-starts-with | |
✅ | str-sub | |
✅ | str-trim | |
✅ | str-upper | |
❌ | string-iter | |
✅ | string? | |
✅ | substitute | |
❌ | summary-stats | |
❌ | supported-types-map | |
❌ | sym | |
❌ | sym->str | |
✅ | symbol? | |
✅ | syntax-off | |
✅ | syntax-on | |
❌ | sys-apply | |
✅ | sys-command? | |
✅ | syscall | Renamed to: sh |
❌ | take | |
❌ | take-iter | |
❌ | tan | |
✅ | temp-dir | |
❌ | third-quartile | |
❌ | time | |
❌ | timer | |
❌ | to-degrees | |
❌ | to-radians | |
✅ | tok-default-color | |
✅ | tok-invalid-color | |
✅ | tok-slsh-fcn-color | |
✅ | tok-slsh-form-color | |
✅ | tok-string-color | |
✅ | tok-sys-alias-color | |
✅ | tok-sys-command-color | |
❌ | token-delim | |
❌ | true? | |
✅ | type | |
❌ | umask | |
❌ | unalias | |
❌ | undef | |
❌ | unexport | |
❌ | unregister-alias | |
❌ | unwind-protect | |
❌ | valid-first-arg? | |
❌ | values | |
❌ | values-length | |
❌ | values-nth | |
❌ | values? | |
❌ | var | |
❌ | var-or-env | |
✅ | vec | |
❌ | vec-clear! | |
❌ | vec-empty? | |
❌ | vec-insert! | |
❌ | vec-iter | |
❌ | vec-nth | |
✅ | vec-pop! | |
✅ | vec-push! | |
❌ | vec-remove! | |
❌ | vec-set! | |
✅ | vec-slice | |
✅ | vec? | |
☑️ | verify-all-options-valid | Leftover from getopts implementation. |
☑️ | verify-arity | Leftover from getopts implementation. |
❌ | version | |
❌ | wait | |
✅ | when | |
❌ | with-padding | |
✅ | with-temp | |
✅ | with-temp-file | |
❌ | write-line | |
❌ | write-string | |
✅ | xar! | |
✅ | xdr! |
[Slosh Rust Docs]
[All Rust Docs]
[Legacy sl-sh Documentation]