Skip to content

dpbriggs/x7

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

The x7 Programming Language

x7 is a lisp I built to better understand programming languages and interpreters.

The standard library is being written in either x7 or rust for performance.

Features

Usual Lispy Goodness

You have brackets. Lots of brackets. And lists. And functions.

Self-documenting

The goal is to have every function describe itself, so you can live in the repl.

Use the doc function on a symbol to see it’s documentation:

>>> (print (doc foreach))
Eagerly apply the given function to a sequence or list.
Example:
(foreach
  (fn (x) (println x))
  (range 20)) ; prints 0 to 20. Returns ().

(foreach
  (fn (x) (println x))
  (take 5 (map (fn (x) (* x x x x x x)) (range)))) ; prints 0, 1, 64, 729, 4096

The general goal is to be as helpful as possible. So stacktraces include more information than you’d usually get, such as arguments.

For example, the following program will fail:

(defn bottom (x) (% x 2))
(defn middle (x) (bottom x))
(defn top () (middle "a"))
(top)

And give this helpful stacktrace:

Error: BadTypes

Stacktrace:
  - Remainder requires left and right are num types, was given "a" % 2
  - Error in Fn<%, 2, [ ]>, with args ("a" 2)
  - Error in Fn<bottom, 1, [ x ]>, with args ("a")
  - Error in Fn<middle, 1, [ x ]>, with args ("a")
  - Error in Fn<top, 0, [ ]>, with args ()

Convenient FFI

x7 offers easy and convenient embedding into other rust programs.

use x7::ffi::{X7Interpreter, ForeignData};

let interpreter = X7Interpreter::new();
let res = interpreter.run_program::<u64>("(+ 1 1)").unwrap();
assert_eq!(res, 2);

You can interface your own types in x7 with the ForeignData trait, and add foreign functions into the interpreter. To maximize convenience foreign functions are typed in terms of their own datatypes - not x7’s Expr type.

let interpreter = X7Interpreter::new();
let my_sum_fn = |args: Vec<u64>| Ok(args.iter().sum());
// Add the my-sum to interpreter
interpreter.add_function("my-sum", 1, Arc::new(my_sum_fn));

// And verify we get u64 with value 6 out of it.
assert_eq!(interpreter.run_program::<u64>("(my-sum 1 2 3)").unwrap(), 6);

More interesting is the fact that functions added to the interpreter in a strongly typed way, allowing us to mix types!

// Recall that my-sum is a Fn(Vec<u64>) -> u64
let string_res = interpreter.run_program::<String>("(my-sum 1 2 3)").unwrap();
// And we get a string out it!
assert_eq!(string_res, "6".to_string());

The reason it works is we embed the type information into the function added to the interpreter, and x7’s Expr type acts as a bridge between types.

For more info see the ffi.rs example in the examples folder!

You can run the example with:

cargo run --example ffi

Speedy Iterators

Certain constructs like (range) and map are backed by lazy iterators, making them pretty fast.

Examples

Fibonacci Numbers

We can print the first hundred fibonacci numbers in 14 milliseconds:

;; fib.x7
;; Run with: x7 fib.x7

;; Map (l, r) -> (r, l + r)

(defn fib-step (x)
  (bind ((l r) x) ^(r (+ l r))))

;; Reduce (0 1) `num` times using fib-step to
;; generate the `num`'th fibonacci number

(defn fib (num)
  (nth 0 (reduce
          fib-step
          (tuple 0 1)
          (range num))))

;; Print one hundred fibonacci numbers
;;
;; Note: (take 100 (map fib (range)))
;; is an iterator which maps to Rust's iterators which
;; makes them very fast. No weird intermediate allocations.

(println (time (foreach
                println
                (take 100 (map fib (range))))))

Outputs:

0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
...truncated...
83621143489848422977
135301852344706746049
218922995834555169026

More Features

Dynamic Records and Syntactic Sugar

A recent addition to the language is the defrecord and defmethod functions, which allow you to define records in x7 and add methods to the them respectively.

Here’s an example of defining Vec3, and a way to add them together:

;; Define a record
(defrecord Vec3 "Three dimensional vector" x y z)

;; Add a method to it
(defmethod Vec3 +
  "Add two vectors together"
  (other)
  (Vec3
   (+ other.x self.x)
   (+ other.y self.y)
   (+ other.z self.z)))

This lets us encapsulate data, and access it in a nice structured way.

;; Instantiate a Vec3
(def my-vector (Vec3 1 1 1))

;; Call the + method
(.+ my-vector my-vector) ;; Record<Vec3, fields=[ x: 2 y: 2 z: 2 ]>

The process of adding this support added two new ways to interact with expressions - callable Records and field-access-sugar

Callable Records

To make record construction nice, you can treat records defined with defrecord as constructor functions:

>>> (defrecord Point x y)
Record<Point, uninitialized>
>>> (Point 0 0)
Record<Point, fields=[ x: 0 y: 0 ]>

Record Field Syntactic Sugar

By default, fields of a record are treated as zero-arity methods on that record, with self being inserted with method_call syntax.

This meant that this got old after a while:

(+ (.x self) (.x other))

So I added some sugar in the form of self.x:

>>> (defrecord Point x y)
>>> (def origin (Point 0 0))
>>> origin.x
0

It works in a recursive way if you have deeply nested fields.

>>> (defrecord Point x y)
>>> (defrecord Space origin)
>>> (def space (Space (Point 0 0)))
>>> space.origin
Record<Point, fields=[ x: 0 y: 0 ]>
>>> space.origin.x
0
>>> space.origin.y
0

The syntax immediately evaluates, as it gets transformed a nested list of function calls:

space.origin.y ;; (.y (.origin space))

You can do some tricks with this, like this:

(def file (fs::open "input.txt"))
(def re (re::compile "(\d+)-(\d+) (.): (.*)"))
(def captures (.captures re file.read_to_string))

Zero arity functions can also be referenced:

>>> (def v (Vec3 1 1 1))
nil
>>> v.scale
Fn<curried_method_call<Vec3<scale>; #args=1>, 0, [ ]>
>>> (v.scale 3)
Record<Vec3, fields=[ x: 3 y: 3 z: 3 ]>
>>> v.length
1.73205080

Anonymous Function Syntactic Sugar

You can easily create anonymous functions with #(...). Here’s an example:

(filter #(< $1 10) (range 100)) ;; (0 1 2 3 4 5 6 7 8 9)

(map #(+ 10 $1) (range 10)) ;; (10 11 12 13 14 15 16 17 18 19)

Fields are labelled $1, $2, ....

Language Description

x7 is a quirky lisp which sort of evolved naturally. It has the following data-types:

  pub enum Expr {
    Num(Num),
    Integer(Integer),
    Symbol(Symbol),
    List(Vector<Expr>),
    Function(Arc<Function>),
    Nil,
    String(String),
    Quote(Vector<Expr>),
    Tuple(Vector<Expr>),
    Bool(bool),
    LazyIter(IterType),
    Dict(Dict),
    Record(crate::records::RecordType),
}

Num

Numbers in x7 are arbitrary precision BigDecimal types backed by the bigdecimal crate.

Example:

0
0.0
1.1
1000000000000000000

Integer

A fast-path for integer heavy calculations. If you can avoid non-whole numbers this is substantially faster than the Num type.

Example:

1
2
-5

Symbol

Symbols are references to some object in the symbol table. They can’t contain quotes or brackets.

Example:

+
sort
doc

List

A list is a sequential collection of values. When evaluated, the first argument is called as a function with the rest of the elements as arguments.

Example:

(+ 1 2)
(println "hello world!")

Function

A function is a type defined by the fn or defn keywords. They accept a variable number of arguments and carry a local scope. Variables shadow each other, and functions will close over arguments.

Example:

(defn is-odd?
  (x)
  (= 1 (% x 2))) ; add function is-odd? to symbol table

(map
  (fn (num) (* num num)) ; anon func
  (range 20))

(defn not=
  (& args) ; excess variables can be captured into a list
  (not (apply = args)))

Nil

Null type. Usually equal to an empty list.

String

A UTF-8 string of characters between two quotes: “hello world!”

Quote

An unevaluated list. When evaluated, it turns into a list.

Has special syntax: =’(1 2 3)= And a keyword: (quote 1 2 3)

Tuple

Same thing as a list, but always evals to itself.

Has special syntax: ^(1 2 3) And a keyword: (tuple 1 2 3)

Bool

Classic boolean. True or false.

Example:

true
false
(= 1 0) ;; false

LazyIter

A sequence of values backed by a Rust iterator. These are useful for working with infinite sequences.

Currently, map, filter, take, and range can yield lazy iterators.

They are evaluated with doall to make a list or foreach to operate on it.

Example:

(doall (take 5 (map inc (range)))) ; (1 2 3 4 5)
; Or
(foreach
  println
  (take 5 (map inc (range)))) ; prints one through five

Dict

Classic immutable dictionary. This is certainly a work in progress.

Example:

(def foo (dict "key1" "value1" 3 4))

(get foo 3)  ;; 4
(get foo "key1")  ;; "value1"

(set foo 5 6)  ;; {"key1": "value1", 3: 4, 5: 6}
               ;; This does not mutate `foo`!
(get foo 5)  ;; nil

Record

Objects in x7. See the record section above.

Standard Library Reference

The x7 language has self-documenting features. The standard library reference is generated with the script below, which org-mode pastes into the list below:

(defn pretty-print
  "Format doc strings into something org-mode will agree with."
  (x)
  (bind
   ((sym docu) x)
   (do
       (println "*** =" sym "=")
       (println "")
       (println "#+BEGIN_SRC elisp")
       (println docu)
       (println "#+END_SRC")
       (println ""))))

(foreach
 pretty-print
 (zip (all-symbols) (map doc (all-symbols))))

+

Add two items together. Concatenates strings, lists, and tuples.
Example: (+ 1 1 1) ; 3
Example: (+ "Hello " "World") ; "Hello World"

-

Subtracts all items from the first. Only works with Nums.
Example: (- 2 1 1) ; 0

*

Multiply all items against the first. Works with Nums and (String Num*)
Example: (* 1 2 3) ; 6
         (* "abc" 3) ; "abcabcabc"

%

Take the remainder of the first item against the second.
    Example: (% 4 2) ; 0

/

Divide the first element by the rest.
Example: (/ 8 2 2 2) ; 1

sqrt

Take the square root of a number. There's minor precision loss as it's way faster to convert to floats internally over using a bigdecimal.
Example: (sqrt 9) ; 3

===

Test if all items are equal.
Example: (= 1 1) ; true
         (= 1) ; true

<

Test if the first item is strictly smaller than the rest.
    Example: (< 0 1 2) ; true

<=

Test if the first item is smaller or equal to the rest.
    Example: (<= 0 0 0.05 1) ; true

>

Test if the first item is strictly greater than the rest.
    Example: (> 10 0 1 2 3 4) ; true

>=

Test if the first item is greater than or equal to the rest.
    Example: (>= 10 10 5) ; true

inc

Increment the given number.
Example:
(inc 2.2) ;; 3.3
(inc 1) ;; 2

dec

Decrement the given number.
Example:
(dec 2.2) ;; 3.3
(dec 1) ;; 2

pow

Raise a number to an exponent.
Example:
(pow 2 3) ;; 8
(pow 10 3) ;; 1000

floor

Floor a number.
Example:
(floor 5.5) ;; 5.5

int

Create an integer from the input.

Example:
(int 3.2) ;; 3

not

Invert the bool. true becomes false and vice-versa.

or

logical or.

and

logical and.

xor

logical xor.

ident

Identity function. Returns what you give it.

quote

Transforms the given input into a quote. Usually you will want to use the '(1 2 3) syntax.

symbol

Turn a string into a symbol

str

Make a string

bool

Coerce a value to bool. In general if a collection is non-empty, it is true. The len method is called on Records

print

Print the given argument WITHOUT a newline.

println

Print the given argument WITH a newline.

input

Get user input from stdin

split

Split a string with some substring.
Example:
>>> (split "," "hello, world")
(tuple "hello" " world")

replace

Replace a substring in a string with some other string.
Example:
>>> (replace "abc" "OwO" "abc def")
"OwO def"

ident-exists

Returns true if a given symbol exists in the interpeter

eval

Eval an expression.
Example (in repl):
>>> '(+ 1 2)
(+ 1 2)
>>> (eval '(+ 1 2))
3

parse

Parse an expression.
Example (in repl):
>>> (parse "(+ 1 2)")

def

Associate a given symbol with a value. Overwrites local variables.
Example:
>>> (def a 3)
>>> a
3

cond

Branching control flow construct. Given an even list of [pred then], if `pred` is true, return `then`.
Example:
(def input 10)
(cond
  (= input 3)  (print "input is 3")
  (= input 10) (print "input is 10")
  true         (print "hit base case, input is: " input))

loop

Not done yet. Loop in a weird way. Repeatedly runs the body until (break) is called.

match

Branching control flow construct. Given an item and an even list of [value then], if `item` == `value`, return `then`.
Example:
(def input 10)
(match input
  3  (print "input is 3")
  10 (print "input is 10")
  _  (print "hit base case, input is: " input))

if

Branching control flow construct. Given pred?, then, and else, if pred? is true, return then, otherwise, else.
Note: Does not evaluate branches not taken.
Example:
(def input 10)
(if (= input 10)
  (print "input is 10!")
  (print ":[ input is not 10"))

shuffle

Shuffle (randomize) a given list.
Example:
>>> (shuffle (range 10))
(6 3 2 9 4 0 1 8 5 7)

go

Run a function in a new thread. Example:
(go (fn ()
        (do
         (sleep 2)
         (println "from another thread!"))))

;; After two seconds, something is printed

chan

Make a channel. Returns a tuple of (writer, reader). Example:
(bind
 ((w r) (chan))
 (do
   (go (fn () (print-recv r)))
   (.send w "in bind context 1")
   (sleep 1)
   (.send w "in bind context 2")
   (.close w)
  ))

;; Two things are printed.

random_bool

Randomly return true or false.

random_int

Randomly return an integer between lower and upper.

Example:
(random_int 0 10) ;; Returns a num between 0 and 10 (exclusive)

panic

Abort the program printing the given message.

Example: (panic "goodbye") ; kills program

Your console will print the following:

thread 'main' panicked at 'goodbye', src/stdlib.rs:216:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

... and the interpreter will stop.

primes

Prime numbers less than `n`.

divisors

Divisors of `n`. Example:
    (divisors 20) ;; ^(1 2 4 5 10 20)

clrf

HACK! Returns 
 as the parser is buggy atm.
    Example: (clrf) ; "
"

timestamp

Returns a unix timestamp.
    Example: (timestamp "%b %-d, %-I:%M") ; "Jul 2, 5:15"

name-of

Returns the name of the object.
    Example: (name-of +) ; "+"

sleep

Sleep for n seconds.
    Example: (sleep 10) ; sleep for 10 seconds.

type

Return the type of the argument as a string.
    Example: (type "hello") ; str

doc

Return the documentation of a symbol as a string.
    Example: (doc doc) ; Return the documentation of a symbol as a...

err

Return an error with a message string.
    Example: (err "Something bad happened!") ; return an error

all-symbols

Return all symbols defined in the interpreter.

include

Include a file into the interpreter.

map

Apply a function to each element of a sequence and return a list.
Example: (map inc '(1 2 3)) ; (2 3 4)

mapt

Apply a function to each element of a sequence and return a tuple.
Example: (map inc '(1 2 3)) ; ^(2 3 4)

->

DOCS TBD

inline_transform

Given a list of data and another of functions, apply each function pairwise onto the list.
Example:

(defn adder-maker (x) (fn (y) (+ x y)))

(inline_transform
  '(1 1 1)
   (list (adder-maker 1) (adder-maker 2) (adder-maker 3)))  ;; ^(2 3 4)

foreach

Eagerly apply the given function to a sequence or list.
Example:
(foreach
  (fn (x) (println x))
  (range 20)) ; prints 0 to 20. Returns ().

(foreach
  (fn (x) (println x))
  (take 5 (map (fn (x) (* x x x x x x)) (range)))) ; prints 0, 1, 64, 729, 4096

filter

Retain elements in a sequence according to a predicate.
Example:
(defn is-odd (x) (= 1 (% x 2)))
(filter is-odd (range 20)) ; outputs (1 3 5 7 9 11 13 15 17 19)

any

Ask whether a predicate is true in some sequence. Short circuits.

all

Ask whether a predicate is true for every element of a sequence. Short circuits.

lazy

Turn a list into a lazy sequence. Useful for building complex iterators over some source list.

skip

Skip some amount in a lazy iterator.

product

Cartesian Product every list passed in.
Example:
>>> (doall (product '(0 1) '(0 1) '(0 1)))
(
  (tuple 0 0 0)
  (tuple 1 0 0)
  (tuple 0 1 0)
  (tuple 1 1 0)
  (tuple 0 0 1)
  (tuple 1 0 1)
  (tuple 0 1 1)
  (tuple 1 1 1)
)

apply

Apply a function to a given list.
(def my-list '(1 2 3))
(apply + my-list) ; outputs 6

do

Evaluate a sequence of expressions and return the last one.
Example:
(defn complex-fn (x)
  (do
    (print "current state: " x)
    (+ x x)))

partial

;; Construct a partial function.

;; Example:
(defn foobar (x y z) (+ x y z))

(def part (partial foobar 1 2))
(part 3) ;; 6

((partial foobar 1) 0 -1) ;; 0

(partial + 1) ;; Fn<Partial<Fn<+, 1, [ ]>; remaining=0>, 0, [ ]>

comp

Compose given functions and return a new function. NOT IMPLEMENTED YET!

reduce

Reduce (fold) a given sequence using the given function. Reduce is multi-arity, and will accept an `init` parameter.
Example:
(reduce + '(1 2 3)) ; 6
(reduce + 100 '(1 2 3)) ; 106

fn

Create a anonymous function.
Example:
(fn (x) (* x 2)) ; Fn<AnonFn, 1, [ x ]>

defn

Define a function and add it to the symbol table. Supports doc strings.
Example:
(defn is-odd? (x) (= 1 (% x 2)))
(defn get-odd-numbers
  "Extract the odd numbers out of the given sequence `x`"
  (x)
  (filter is-odd? x)) ; for fun, try (doc get-odd-numbers)

anon-fn-sugar

Create an anonymous, automatic binding function. You normally want to use the #(+ 1 2) syntax. Fields are labelled $1, $2, $3, and so on.

Example:

(#(+ $1 $2) 1 2) ;; 3
(anon-fn-sugar (+ $1 $2)) ;; Fn<AnonFn, 0, [ ]>


Note: This currently does not capture values.

;; >>> (def foo (fn (x) #(+ $1 x)))
;; nil
;; >>> ((foo 3) 5)
;; Error: Unknown Symbol x
;;
;; Stacktrace:
;;   - Error in Fn<AnonFn, 0, [ ]>, with args (5)

bind

Bind symbol-value pairs, adding them to the symbol table.
Example:
(defn quicksort
  "Sort a list."
  (l)
  (cond
   (empty? l) l
   true (bind
         (pivot (head l)
          rest  (tail l)
          le    (filter (fn (x) (<= x pivot)) rest)
          ge    (filter (fn (x) (> x pivot)) rest))
         (+ (quicksort le) (list pivot) (quicksort ge)))))

;; Bind also supports list patterns
(bind ((x y) '(1 2)) (+ x y)) ;; 3

take

Take the first `n` items from a list or sequence.
Example:
(take 2 '(1 2 3)) ; (1 2)
(take 5 (range)) ; lazy seq of (0 1 2 3 4)
(doall (take 5 (range))) ; (0 1 2 3 4)

find

Find and return some value matching a predicate in an iterator.

Note: This will stop iterating once it's found an item. If nothing is found, nil is returned.

Example:

>>> (find #(= $1 3) (take 4 (range)))
3
>>> (find #(= $1 300) (take 4 (range)))
nil

slice

Slice a list.
Example:

>>> (def ll '(1 2 3 4 5 6))
nil
>>> (slice 0 2 ll)
(tuple 1 2)

take-while

Continue taking items while `pred` is true.
Example:
(defn less-than-five (x) (< x 5))
(doall (take-while less-than-five (range))) ; (0 1 2 3 4)
(take 2 '(1 2 3)) ; (1 2)
(take 5 (range)) ; lazy seq of (0 1 2 3 4)
(doall (take 5 (range))) ; (0 1 2 3 4)

doall

Evaluate a sequence, collecting the results into a list.
Example:
(doall (take 5 (range))) ; (0 1 2 3 4)

dict

Create a dict from the given elements.
Example:
(dict "a" 1 "b" 2) ;

assoc

Create a new dict from an old dict with the given elements.
Example:
(assoc (dict) 1 2 3 4) ; {1: 2, 3: 4}

remove

Remove a key-value pair from a dict.
Example:
(remove (dict 1 2) 1) ; {}

set-dict

Set a key to a value in a dict. It'll return the new dict.
Example:
(set-dict (dict 1 2) 3 4) ; {1: 2, 3: 4}
(get (dict) 1 2) ; {1: 2}

values

Get the values of a dict.
Example:
>>> (values (dict 1 2 3 4))
(tuple 2 4)

get

Get a value from a dict by key.
Example:
(get (dict 1 2) 1) ; 2
(get (dict) 1) ; nil

list

Create a list from the given elements.
Example:
(list 1 2 3) ; (1 2 3)

tuple

Create a list from the given elements.
(tuple 1 2 3) ; (tuple 1 2 3)
;; It's usually easier to use the tuple syntax:
^(1 2 3) ; (tuple 1 2 3)

nth

Extract the nth item from a list or tuple. Throws error if this fails.
Example
(nth 0 ^(1 2 3)) ; 1
(nth 1 '(1 2 3)) ; 2

flatten

Flatten a list of lists.
Example:
>>> (flatten '('(1 2 3) '(4 5 6) 7))
(tuple 1 2 3 4 5 6 7)

chars

Get a tuple of characters from a string.
Example:
(chars "hello") ;; (tuple "h" "e" "l" "l" "o")

head

Get the first item in a list.
Example:
(head ()) ; nil
(head (1 2 3)) ; 1

tail

Get all items after the first in a list or tuple.
(tail '(1 2 3)) ; (2 3)
(tail ^()) ; nil

cons

Push an item to the front of a list.
Example:
(cons 1 '()) ; (1)
(cons 1 '(2 3)) ; (1 2 3)

range

Generate a range of numbers. It accepts 0, 1, or 2 arguments. No arguments
yields an infinite range, one arg stops the range at that arg, and two args denote start..end.
Example:
(range) ; infinite range
(range 5) ; (0 1 2 3 4)
(range 5 10); (5 6 7 8 9)

len

Get the number of items in a list or tuple.
Example:
(len '(0 0 0)) ; 3
(len '()) ; 0

rev

Reverse a list.

zip

Zip two lists together into a list of tuples.

len

Get the number of items in a list or tuple.
Example:
(len '(0 0 0)) ; 3
(len '()) ; 0

sort

Sort a given homogeneously typed list in ascending order. Returns an error if types are all not the same.
Example:
(sort '(3 7 0 5 4 8 1 2 6 9)) ; (0 1 2 3 4 5 6 7 8 9)

distinct

Remove all duplicates from a list. This will sort the list.
Example:
(distinct '(1 1 1 2 2 0 0)) ; (0 1 2)

inspect

Inspect values in a lazy iterator while its running.
Example:
>>> (doall (inspect #(println "curr_item=" $1) (take 3 (range))))
curr_item=0
curr_item=1
curr_item=2
(0 1 2)

max-by

Get the maximum value of an iterator by a some function f. Throws an error if called with an empty iteratable.
Example:
(max-by
  (fn (x) (nth 0 x))
  (lazy (zip (range 10) (range 10)))) ;; (tuple 9 9)

fs::open

Manipulate files in x7.
Example:
(def my-file (fs::open "my_file.txt"))

;; Write to the file
(.write my-file "Hello World")

;; Read from the file
(.read_to_string my-file)

defrecord

Define a Record structure.

Use defmethod to add methods a record.

Example:
;; Define a record
(defrecord Vec3 "Three Dimensional Vector" x y z)

;; Instantiate a Vec3
(def v (Vec 1 2 3))

;; Access attributes

v.x    ;; 1
(.y v) ;; 2

defmethod

Add a method to a record. Cannot be called on instantiated records.

NOTE: Methods get an implicit `self` reference.

;; Example

;; Define a record
(defrecord Vec3 "Three Dimensional Vector" x y z)

(defmethod Vec3 +
  "Add two vectors together"
  (other)
  (Vec3
   (+ other.x self.x)
   (+ other.y self.y)
   (+ other.z self.z)))

(def v (Vec3 1 1 1))

(.+ v v) ;; (Vec3 2 2 2)

call_method

Call a method on a record.

Example:

(def f (fs::open "Hello.txt"))
(call_method f "read_to_string") ;; no args required
(call_method f "write" "hello world") ;; pass it an arg

re::compile

Regular Expressions - regular search patterns.

This is backed by the excellent regex crate: https://github.com/rust-lang/regex

Example:

;; Compile a regex
(def a (re::compile "(abc)+"))

;; Test if a string matches

(.is_match a "abcabc") ;; true
(.is_match a "ab") ;; false

methods

Grab all documentation for a record's methods

time

Return the time taken to evaluate an expression in milliseconds.

catch-err

Catch an error. Returns nil if no error is caught.

interner-stats

Internal string interner stats.

print-smiley-face

print a smiley face

assert-eq

Assert if two items are equal.

TestResult

Result of a test

not=

Test if a sequence is not equal to each other.
Example:
(not= 1 1 2) ; false

empty?

Test if a collection is empty.

non-empty?

Test if a collection is non-empty.

is-even?

Test if the given item is even.

dot-product

Dot product two vectors.
Example:
(dot-product '(1 2 3) '(4 5 6)) ; 32

quicksort

Sort a list using quicksort.
Example:
(quicksort '(3 1 2)) ; (1 2 3)

fib

Find the `num'th Fibonacci number.

docp

Pretty print the doc string of a function
   Example: (docp docp) ;; Pretty print the doc string of a function...

max

Maximum element in a list

first

Get the first item of a collection, or nil. Same as head.

second

Get the second item of a collection, or nil

Set

Basic Hash Set in x7.

;; Contains. Test whether an element exists in a Set. O(1) time.
;; Example:
(.contains (Set 0 1 2 3) 2)  ;; true
(.contains (Set 0 1 2 3) 10) ;; false

;; Union (creates new Set with elements from each)
;; Example:
(.union (Set 1 2 3)
        (Set 4 5 6)) ;; Set<{4, 5, 2, 6, 1, 3}>
(.union (apply Set (range 5)) (apply Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

;; Intersection. Obtain the intersection of two Sets.
;; Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

;; to_list. Convert the Set into a list. Order is undefined.
;; Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

;; len. Get the number of elements in a Set. Implements the "len" magic method.
;; Example:
(.len (Set '(0 1 2 3)))  ;; 4
(len (Set '())) ;; 0

Set.contains

Test whether an element exists in a set. O(1) time.
Example:
(.contains (Set 0 1 2 3) 2)  ;; true
(.contains (Set 0 1 2 3) 10) ;; false

Set.len

Get the number of elements in a Set. Implements the "len" magic method.
Example:
(.len (Set 0 1 2 3))  ;; 4
(len (Set)) ;; 0

Set.union

Obtain the union of two Sets.
Example:
(.union (Set (range 5)) (Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

Set.intersection

Obtain the intersection of two Sets.
Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

Set.to_list

Convert the Set into a list. Order is undefined.
Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

Dict

Immutable dictionary.
Example:
(dict "a" 1 "b" 2) ;

DictMut

Mutable dictionary type

DictMut.Docs

TBD

FileRecord

Manipulate files in x7.
Example:
(def my-file (fs::open "my_file.txt"))

;; Write to the file
(.write my-file "Hello World")

;; Read from the file
(.read_to_string my-file)

FileRecord.read_to_string

Read a files as a string.
Example:
(def my-file (fs::open "my_file.txt"))
(.read_to_string my-file) ; file contents

FileRecord.read_lines

Get all lines of a file as a list.
Example:
(def my-file (fs::open "my_file.txt"))
(.read_lines my-file) ; '("first_line" "second_line")

FileRecord.write

Overwrite the file's content with the given string.
Example:
(def new-file (fs::open "new_file.txt"))
(.write "Hello world!")

FileRecord.append_to_file

Append to a file without a newline.
Example:
(def new-file (fs::open "new_file.txt"))
(.append_to_file "Hello world!") ; file contains '...old-contents...Hello world!'

FileRecord.append_line

Append a string to a file with a newline.
Example:
(def new-file (fs::open "new_file.txt"))
(.append_line "Hello world!") ; file contains '...old-contents...Hello world!
'

Regex

Regular Expressions - regular search patterns.

This is backed by the excellent regex crate: https://github.com/rust-lang/regex

Example:

;; Compile a regex
(def a (re::compile "(abc)+"))

;; Test if a string matches

(.is_match a "abcabc") ;; true
(.is_match a "ab") ;; false

Regex.is_match

Returns true if a string matches the regex.

Example:
(def re (re::compile "abc"))
(assert-eq true (.is_match re "abc") "Did not match!")

Regex.captures

Returns a list of lists of all captures in the input.
;; Example
(def lines "15-16 f: ffffffffffffffhf
             6-8 b: bbbnvbbb
             6-10 z: zhzzzzfzzzzzzzzzpzz
             9-13 s: dmssskssqsssssf")
(def re (re::compile "(\d+)-(\d+) (.): (.*)"))
(.captures re lines)
;; Outputs:
((tuple "15" "16" "f" "ffffffffffffffhf")
 (tuple "6" "8" "b" "bbbnvbbb")
 (tuple "6" "10" "z" "zhzzzzfzzzzzzzzzpzz")
 (tuple "9" "13" "s" "dmssskssqsssssf"))

TcpListenerRecord

Tcp Socket Server TBD

Set

Basic Hash Set in x7.

;; Contains. Test whether an element exists in a Set. O(1) time.
;; Example:
(.contains (Set 0 1 2 3) 2)  ;; true
(.contains (Set 0 1 2 3) 10) ;; false

;; Union (creates new Set with elements from each)
;; Example:
(.union (Set 1 2 3)
        (Set 4 5 6)) ;; Set<{4, 5, 2, 6, 1, 3}>
(.union (apply Set (range 5)) (apply Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

;; Intersection. Obtain the intersection of two Sets.
;; Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

;; to_list. Convert the Set into a list. Order is undefined.
;; Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

;; len. Get the number of elements in a Set. Implements the "len" magic method.
;; Example:
(.len (Set '(0 1 2 3)))  ;; 4
(len (Set '())) ;; 0

Set.contains

Test whether an element exists in a set. O(1) time.
Example:
(.contains (Set 0 1 2 3) 2)  ;; true
(.contains (Set 0 1 2 3) 10) ;; false

Set.len

Get the number of elements in a Set. Implements the "len" magic method.
Example:
(.len (Set 0 1 2 3))  ;; 4
(len (Set)) ;; 0

Set.union

Obtain the union of two Sets.
Example:
(.union (Set (range 5)) (Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

Set.intersection

Obtain the intersection of two Sets.
Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

Set.to_list

Convert the Set into a list. Order is undefined.
Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

WriteChan

Write side of a channel

WriteChan.send

Sent some item into a channel.
;; `w` is some writer
(.send w "Some item 1")

WriteChan.close

Close the writer. This will stop any readers on the channel.

WriteChan.is_closed

Returns true if the channel is closed.

ReadChan

Read side of a channel

ReadChan.recv

Read some item from a channel. This will block until an item is received or the sender is closed. Example:

;; `w` is some writer
(bind
 ((writer reader) (chan))
 (do
   (go (fn () (do (println (.recv r))))) ;; recv items
   (.send writer "item 1")
   (sleep 1)
   (.send writer "item 2")
   (.close writer) ;; "item 1" and "item 2" are printed
  ))

ReadChan.close

Close the reader. This will fail if the reader has been closed.

ReadChan.is_closed

Returns true if the channel is closed.

pretty-print

Format doc strings into something org-mode will agree with.

+

Add two items together. Concatenates strings, lists, and tuples.
Example: (+ 1 1 1) ; 3
Example: (+ "Hello " "World") ; "Hello World"

-

Subtracts all items from the first. Only works with Nums.
Example: (- 2 1 1) ; 0

*

Multiply all items against the first. Works with Nums and (String Num*)
Example: (* 1 2 3) ; 6
         (* "abc" 3) ; "abcabcabc"

%

Take the remainder of the first item against the second.
Example: (% 4 2) ; 0

/

Divide the first element by the rest.
Example: (/ 8 2 2 2) ; 1

sqrt

Take the square root of a number. There's minor precision loss as it's way faster to convert to floats internally over using a bigdecimal.
Example: (sqrt 9) ; 3

===

Test if all items are equal.
Example: (= 1 1) ; true
         (= 1) ; true

<

Test if the first item is strictly smaller than the rest.
Example: (< 0 1 2) ; true

<=

Test if the first item is smaller or equal to the rest.
Example: (<= 0 0 0.05 1) ; true

>

Test if the first item is strictly greater than the rest.
Example: (> 10 0 1 2 3 4) ; true

>=

Test if the first item is greater than or equal to the rest.
Example: (>= 10 10 5) ; true

inc

Increment the given number.
Example:
(inc 2.2) ;; 3.3
(inc 1) ;; 2

dec

Decrement the given number.
Example:
(dec 2.2) ;; 3.3
(dec 1) ;; 2

pow

Raise a number to an exponent.
Example:
(pow 2 3) ;; 8
(pow 10 3) ;; 1000

floor

Floor a number.
Example:
(floor 5.5) ;; 5.5

int

Create an integer from the input.

Example:
(int 3.2) ;; 3

not

Invert the bool. true becomes false and vice-versa.

or

logical or.

and

logical and.

xor

logical xor.

ident

Identity function. Returns what you give it.

quote

Transforms the given input into a quote. Usually you will want to use the '(1 2 3) syntax.

symbol

Turn a string into a symbol

str

Make a string

bool

Coerce a value to bool. In general if a collection is non-empty, it is true. The len method is called on Records

print

Print the given argument WITHOUT a newline.

println

Print the given argument WITH a newline.

split

Split a string with some substring.
Example:
>>> (split "," "hello, world")
(tuple "hello" " world")

replace

Replace a substring in a string with some other string.
Example:
>>> (replace "abc" "OwO" "abc def")
"OwO def"

ident-exists

Returns true if a given symbol exists in the interpeter

eval

Eval an expression.
Example (in repl):
>>> '(+ 1 2)
(+ 1 2)
>>> (eval '(+ 1 2))
3

parse

Parse an expression.
Example (in repl):
>>> (parse "(+ 1 2)")

def

Associate a given symbol with a value. Overwrites local variables.
Example:
>>> (def a 3)
>>> a
3

cond

Branching control flow construct. Given an even list of [pred then], if `pred` is true, return `then`.
Example:
(def input 10)
(cond
  (= input 3)  (print "input is 3")
  (= input 10) (print "input is 10")
  true         (print "hit base case, input is: " input))

match

Branching control flow construct. Given an item and an even list of [value then], if `item` == `value`, return `then`.
Example:
(def input 10)
(match input
  3  (print "input is 3")
  10 (print "input is 10")
  _  (print "hit base case, input is: " input))

if

Branching control flow construct. Given pred?, then, and else, if pred? is true, return then, otherwise, else.
Note: Does not evaluate branches not taken.
Example:
(def input 10)
(if (= input 10)
  (print "input is 10!")
  (print ":[ input is not 10"))

shuffle

Shuffle (randomize) a given list.
Example:
>>> (shuffle (range 10))
(6 3 2 9 4 0 1 8 5 7)

go

Run a function in a new thread. Example:
(go (fn ()
        (do
         (sleep 2)
         (println "from another thread!"))))

;; After two seconds, something is printed

chan

Make a channel. Returns a tuple of (writer, reader). Example:
(bind
 ((w r) (chan))
 (do
   (go (fn () (print-recv r)))
   (.send w "in bind context 1")
   (sleep 1)
   (.send w "in bind context 2")
   (.close w)
  ))

;; Two things are printed.

random_bool

Randomly return true or false.

random_int

Randomly return an integer between lower and upper.

Example:
(random_int 0 10) ;; Returns a num between 0 and 10 (exclusive)

panic

Abort the program printing the given message.

Example: (panic "goodbye") ; kills program

Your console will print the following:

thread 'main' panicked at 'goodbye', src/stdlib.rs:216:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

... and the interpreter will stop.

primes

Prime numbers less than `n`.

divisors

Divisors of `n`. Example:
(divisors 20) ;; ^(1 2 4 5 10 20)

sleep

Sleep for n seconds.
Example: (sleep 10) ; sleep for 10 seconds.

type

Return the type of the argument as a string.
Example: (type "hello") ; str

doc

Return the documentation of a symbol as a string.
Example: (doc doc) ; Return the documentation of a symbol as a...

err

Return an error with a message string.
Example: (err "Something bad happened!") ; return an error

all-symbols

Return all symbols defined in the interpreter.

include

Include a file into the interpreter.

map

Apply a function to each element of a sequence and return a list.
Example: (map inc '(1 2 3)) ; (2 3 4)

inline_transform

Given a list of data and another of functions, apply each function pairwise onto the list.
Example:

(defn adder-maker (x) (fn (y) (+ x y)))

(inline_transform
  '(1 1 1)
   (list (adder-maker 1) (adder-maker 2) (adder-maker 3)))  ;; ^(2 3 4)

foreach

Eagerly apply the given function to a sequence or list.
Example:
(foreach
  (fn (x) (println x))
  (range 20)) ; prints 0 to 20. Returns ().

(foreach
  (fn (x) (println x))
  (take 5 (map (fn (x) (* x x x x x x)) (range)))) ; prints 0, 1, 64, 729, 4096

filter

Retain elements in a sequence according to a predicate.
Example:
(defn is-odd (x) (= 1 (% x 2)))
(filter is-odd (range 20)) ; outputs (1 3 5 7 9 11 13 15 17 19)

any

Ask whether a predicate is true in some sequence. Short circuits.

all

Ask whether a predicate is true for every element of a sequence. Short circuits.

lazy

Turn a list into a lazy sequence. Useful for building complex iterators over some source list.

skip

Skip some amount in a lazy iterator.

product

Cartesian Product every list passed in.
Example:
>>> (doall (product '(0 1) '(0 1) '(0 1)))
(
  (tuple 0 0 0)
  (tuple 1 0 0)
  (tuple 0 1 0)
  (tuple 1 1 0)
  (tuple 0 0 1)
  (tuple 1 0 1)
  (tuple 0 1 1)
  (tuple 1 1 1)
)

apply

Apply a function to a given list.
(def my-list '(1 2 3))
(apply + my-list) ; outputs 6

do

Evaluate a sequence of expressions and return the last one.
Example:
(defn complex-fn (x)
  (do
    (print "current state: " x)
    (+ x x)))

partial

;; Construct a partial function.

;; Example:
(defn foobar (x y z) (+ x y z))

(def part (partial foobar 1 2))
(part 3) ;; 6

((partial foobar 1) 0 -1) ;; 0

(partial + 1) ;; Fn<Partial<Fn<+, 1, [ ]>; remaining=0>, 0, [ ]>

comp

Compose given functions and return a new function. NOT IMPLEMENTED YET!

reduce

Reduce (fold) a given sequence using the given function. Reduce is multi-arity, and will accept an `init` parameter.
Example:
(reduce + '(1 2 3)) ; 6
(reduce + 100 '(1 2 3)) ; 106

fn

Create a anonymous function.
Example:
(fn (x) (* x 2)) ; Fn<AnonFn, 1, [ x ]>

defn

Define a function and add it to the symbol table. Supports doc strings.
Example:
(defn is-odd? (x) (= 1 (% x 2)))
(defn get-odd-numbers
  "Extract the odd numbers out of the given sequence `x`"
  (x)
  (filter is-odd? x)) ; for fun, try (doc get-odd-numbers)

anon-fn-sugar

Create an anonymous, automatic binding function. You normally want to use the #(+ 1 2) syntax. Fields are labelled $1, $2, $3, and so on.

Example:

(#(+ $1 $2) 1 2) ;; 3
(anon-fn-sugar (+ $1 $2)) ;; Fn<AnonFn, 0, [ ]>


Note: This currently does not capture values.

;; >>> (def foo (fn (x) #(+ $1 x)))
;; nil
;; >>> ((foo 3) 5)
;; Error: Unknown Symbol x
;;
;; Stacktrace:
;;   - Error in Fn<AnonFn, 0, [ ]>, with args (5)

bind

Bind symbol-value pairs, adding them to the symbol table.
Example:
(defn quicksort
  "Sort a list."
  (l)
  (cond
   (empty? l) l
   true (bind
         (pivot (head l)
          rest  (tail l)
          le    (filter (fn (x) (<= x pivot)) rest)
          ge    (filter (fn (x) (> x pivot)) rest))
         (+ (quicksort le) (list pivot) (quicksort ge)))))

;; Bind also supports list patterns
(bind ((x y) '(1 2)) (+ x y)) ;; 3

take

Take the first `n` items from a list or sequence.
Example:
(take 2 '(1 2 3)) ; (1 2)
(take 5 (range)) ; lazy seq of (0 1 2 3 4)
(doall (take 5 (range))) ; (0 1 2 3 4)

find

Find and return some value matching a predicate in an iterator.

Note: This will stop iterating once it's found an item. If nothing is found, nil is returned.

Example:

>>> (find #(= $1 3) (take 4 (range)))
3
>>> (find #(= $1 300) (take 4 (range)))
nil

slice

Slice a list.
Example:

>>> (def ll '(1 2 3 4 5 6))
nil
>>> (slice 0 2 ll)
(tuple 1 2)

take-while

Continue taking items while `pred` is true.
Example:
(defn less-than-five (x) (< x 5))
(doall (take-while less-than-five (range))) ; (0 1 2 3 4)
(take 2 '(1 2 3)) ; (1 2)
(take 5 (range)) ; lazy seq of (0 1 2 3 4)
(doall (take 5 (range))) ; (0 1 2 3 4)

doall

Evaluate a sequence, collecting the results into a list.
Example:
(doall (take 5 (range))) ; (0 1 2 3 4)

dict

Create a dict from the given elements.
Example:
(dict "a" 1 "b" 2) ;

assoc

Create a new dict from an old dict with the given elements.
Example:
(assoc (dict) 1 2 3 4) ; {1: 2, 3: 4}

remove

Remove a key-value pair from a dict.
Example:
(remove (dict 1 2) 1) ; {}

set-dict

Set a key to a value in a dict. It'll return the new dict.
Example:
(set-dict (dict 1 2) 3 4) ; {1: 2, 3: 4}
(get (dict) 1 2) ; {1: 2}

values

Get the values of a dict.
Example:
>>> (values (dict 1 2 3 4))
(tuple 2 4)

get

Get a value from a dict by key.
Example:
(get (dict 1 2) 1) ; 2
(get (dict) 1) ; nil

list

Create a list from the given elements.
Example:
(list 1 2 3) ; (1 2 3)

tuple

Create a list from the given elements.
(tuple 1 2 3) ; (tuple 1 2 3)
;; It's usually easier to use the tuple syntax:
^(1 2 3) ; (tuple 1 2 3)

nth

Extract the nth item from a list or tuple. Throws error if this fails.
Example
(nth 0 ^(1 2 3)) ; 1
(nth 1 '(1 2 3)) ; 2

flatten

Flatten a list of lists.
Example:
>>> (flatten '('(1 2 3) '(4 5 6) 7))
(tuple 1 2 3 4 5 6 7)

chars

Get a tuple of characters from a string.
Example:
(chars "hello") ;; (tuple "h" "e" "l" "l" "o")

head

Get the first item in a list.
Example:
(head ()) ; nil
(head (1 2 3)) ; 1

tail

Get all items after the first in a list or tuple.
(tail '(1 2 3)) ; (2 3)
(tail ^()) ; nil

cons

Push an item to the front of a list.
Example:
(cons 1 '()) ; (1)
(cons 1 '(2 3)) ; (1 2 3)

range

Generate a range of numbers. It accepts 0, 1, or 2 arguments. No arguments
yields an infinite range, one arg stops the range at that arg, and two args denote start..end.
Example:
(range) ; infinite range
(range 5) ; (0 1 2 3 4)
(range 5 10); (5 6 7 8 9)

len

Get the number of items in a list or tuple.
Example:
(len '(0 0 0)) ; 3
(len '()) ; 0

rev

Reverse a list.

zip

Zip two lists together into a list of tuples.

len

Get the number of items in a list or tuple.
Example:
(len '(0 0 0)) ; 3
(len '()) ; 0

sort

Sort a given homogeneously typed list in ascending order. Returns an error if types are all not the same.
Example:
(sort '(3 7 0 5 4 8 1 2 6 9)) ; (0 1 2 3 4 5 6 7 8 9)

distinct

Remove all duplicates from a list. This will sort the list.
Example:
(distinct '(1 1 1 2 2 0 0)) ; (0 1 2)

max-by

Get the maximum value of an iterator by a some function f. Throws an error if called with an empty iteratable.
Example:
(max-by
  (fn (x) (nth 0 x))
  (lazy (zip (range 10) (range 10)))) ;; (tuple 9 9)

fs::open

Manipulate files in x7.
Example:
(def my-file (fs::open "my_file.txt"))

;; Write to the file
(.write my-file "Hello World")

;; Read from the file
(.read_to_string my-file)

defrecord

Define a Record structure.

Use defmethod to add methods a record.

Example:
;; Define a record
(defrecord Vec3 "Three Dimensional Vector" x y z)

;; Instantiate a Vec3
(def v (Vec 1 2 3))

;; Access attributes

v.x    ;; 1
(.y v) ;; 2

defmethod

Add a method to a record. Cannot be called on instantiated records.

NOTE: Methods get an implicit `self` reference.

;; Example

;; Define a record
(defrecord Vec3 "Three Dimensional Vector" x y z)

(defmethod Vec3 +
  "Add two vectors together"
  (other)
  (Vec3
   (+ other.x self.x)
   (+ other.y self.y)
   (+ other.z self.z)))

(def v (Vec3 1 1 1))

(.+ v v) ;; (Vec3 2 2 2)

call_method

Call a method on a record.

Example:

(def f (fs::open "Hello.txt"))
(call_method f "read_to_string") ;; no args required
(call_method f "write" "hello world") ;; pass it an arg

re::compile

Regular Expressions - regular search patterns.

This is backed by the excellent regex crate: https://github.com/rust-lang/regex

Example:

;; Compile a regex
(def a (re::compile "(abc)+"))

;; Test if a string matches

(.is_match a "abcabc") ;; true
(.is_match a "ab") ;; false

methods

Grab all documentation for a record's methods

time

Return the time taken to evaluate an expression in milliseconds.

catch-err

Catch an error. Returns nil if no error is caught.

interner-stats

Internal string interner stats.

assert-eq

Assert if two items are equal.

TestResult

Result of a test

not=

Test if a sequence is not equal to each other.
Example:
(not= 1 1 2) ; false

empty?

Test if a collection is empty.

non-empty?

Test if a collection is non-empty.

is-even?

Test if the given item is even.

dot-product

Dot product two vectors.
Example:
(dot-product '(1 2 3) '(4 5 6)) ; 32

quicksort

Sort a list using quicksort.
Example:
(quicksort '(3 1 2)) ; (1 2 3)

fib

Find the `num'th Fibonacci number.

docp

Pretty print the doc string of a function
   Example: (docp docp) ;; Pretty print the doc string of a function...

max

Maximum element in a list

Set

Basic Hash Set in x7.

;; Contains. Test whether an element exists in a Set. O(1) time.
;; Example:
(.contains (Set 0 1 2 3) 2)  ;; true
(.contains (Set 0 1 2 3) 10) ;; false

;; Union (creates new Set with elements from each)
;; Example:
(.union (Set 1 2 3)
        (Set 4 5 6)) ;; Set<{4, 5, 2, 6, 1, 3}>
(.union (apply Set (range 5)) (apply Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

;; Intersection. Obtain the intersection of two Sets.
;; Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

;; to_list. Convert the Set into a list. Order is undefined.
;; Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

;; len. Get the number of elements in a Set. Implements the "len" magic method.
;; Example:
(.len (Set '(0 1 2 3)))  ;; 4
(len (Set '())) ;; 0

Set.contains

Test whether an element exists in a set. O(1) time.
Example:
(.contains (Set 0 1 2 3) 2)  ;; true
(.contains (Set 0 1 2 3) 10) ;; false

Set.len

Get the number of elements in a Set. Implements the "len" magic method.
Example:
(.len (Set 0 1 2 3))  ;; 4
(len (Set)) ;; 0

Set.union

Obtain the union of two Sets.
Example:
(.union (Set (range 5)) (Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

Set.intersection

Obtain the intersection of two Sets.
Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

Set.to_list

Convert the Set into a list. Order is undefined.
Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

Dict

Immutable dictionary.
Example:
(dict "a" 1 "b" 2) ;

DictMut

Mutable dictionary type

DictMut.Docs

TBD

FileRecord

Manipulate files in x7.
Example:
(def my-file (fs::open "my_file.txt"))

;; Write to the file
(.write my-file "Hello World")

;; Read from the file
(.read_to_string my-file)

FileRecord.read_to_string

Read a files as a string.
Example:
(def my-file (fs::open "my_file.txt"))
(.read_to_string my-file) ; file contents

FileRecord.read_lines

Get all lines of a file as a list.
Example:
(def my-file (fs::open "my_file.txt"))
(.read_lines my-file) ; '("first_line" "second_line")

FileRecord.write

Overwrite the file's content with the given string.
Example:
(def new-file (fs::open "new_file.txt"))
(.write "Hello world!")

FileRecord.append_to_file

Append to a file without a newline.
Example:
(def new-file (fs::open "new_file.txt"))
(.append_to_file "Hello world!") ; file contains '...old-contents...Hello world!'

FileRecord.append_line

Append a string to a file with a newline.
Example:
(def new-file (fs::open "new_file.txt"))
(.append_line "Hello world!") ; file contains '...old-contents...Hello world!
'

Regex

Regular Expressions - regular search patterns.

This is backed by the excellent regex crate: https://github.com/rust-lang/regex

Example:

;; Compile a regex
(def a (re::compile "(abc)+"))

;; Test if a string matches

(.is_match a "abcabc") ;; true
(.is_match a "ab") ;; false

Regex.is_match

Returns true if a string matches the regex.

Example:
(def re (re::compile "abc"))
(assert-eq true (.is_match re "abc") "Did not match!")

Regex.captures

Returns a list of lists of all captures in the input.
;; Example
(def lines "15-16 f: ffffffffffffffhf
             6-8 b: bbbnvbbb
             6-10 z: zhzzzzfzzzzzzzzzpzz
             9-13 s: dmssskssqsssssf")
(def re (re::compile "(\d+)-(\d+) (.): (.*)"))
(.captures re lines)
;; Outputs:
((tuple "15" "16" "f" "ffffffffffffffhf")
 (tuple "6" "8" "b" "bbbnvbbb")
 (tuple "6" "10" "z" "zhzzzzfzzzzzzzzzpzz")
 (tuple "9" "13" "s" "dmssskssqsssssf"))

Set

Basic Hash Set in x7.

;; Contains. Test whether an element exists in a Set. O(1) time.
;; Example:
(.contains (Set 0 1 2 3) 2)  ;; true
(.contains (Set 0 1 2 3) 10) ;; false

;; Union (creates new Set with elements from each)
;; Example:
(.union (Set 1 2 3)
        (Set 4 5 6)) ;; Set<{4, 5, 2, 6, 1, 3}>
(.union (apply Set (range 5)) (apply Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

;; Intersection. Obtain the intersection of two Sets.
;; Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

;; to_list. Convert the Set into a list. Order is undefined.
;; Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

;; len. Get the number of elements in a Set. Implements the "len" magic method.
;; Example:
(.len (Set '(0 1 2 3)))  ;; 4
(len (Set '())) ;; 0

Set.contains

Test whether an element exists in a set. O(1) time.
Example:
(.contains (Set 0 1 2 3) 2)  ;; true
(.contains (Set 0 1 2 3) 10) ;; false

Set.len

Get the number of elements in a Set. Implements the "len" magic method.
Example:
(.len (Set 0 1 2 3))  ;; 4
(len (Set)) ;; 0

Set.union

Obtain the union of two Sets.
Example:
(.union (Set (range 5)) (Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

Set.intersection

Obtain the intersection of two Sets.
Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

Set.to_list

Convert the Set into a list. Order is undefined.
Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

WriteChan

Write side of a channel

WriteChan.send

Sent some item into a channel.
;; `w` is some writer
(.send w "Some item 1")

WriteChan.close

Close the writer. This will stop any readers on the channel.

WriteChan.is_closed

Returns true if the channel is closed.

ReadChan

Read side of a channel

ReadChan.recv

Read some item from a channel. This will block until an item is received or the sender is closed. Example:

;; `w` is some writer
(bind
 ((writer reader) (chan))
 (do
   (go (fn () (do (println (.recv r))))) ;; recv items
   (.send writer "item 1")
   (sleep 1)
   (.send writer "item 2")
   (.close writer) ;; "item 1" and "item 2" are printed
  ))

ReadChan.close

Close the reader. This will fail if the reader has been closed.

ReadChan.is_closed

Returns true if the channel is closed.

pretty-print

Format doc strings into something org-mode will agree with.

Thanks

A big thanks to the nom people (Geal et all) for having an s_expression example for my parser!

About

Speedy self-documenting lisp in Rust.

Topics

Resources

License

Stars

Watchers

Forks

Languages