Go to file
2024-03-01 19:51:32 -05:00
matrix-bin comments 2024-03-01 19:51:32 -05:00
matrix-lang comments 2024-03-01 19:51:32 -05:00
matrix-macros remove unwraps, fix utf8 2024-02-29 21:05:10 -05:00
matrix-std remove unwraps, fix utf8 2024-02-29 21:05:10 -05:00
.gitignore new lang => lexer and parser done 2024-02-15 23:07:30 -05:00
Cargo.lock fin prob 2024-02-29 17:04:28 -05:00
Cargo.toml fin prob 2024-02-29 17:04:28 -05:00
LICENSE docs 2024-02-15 23:10:48 -05:00
README.md fix readme 2024-02-29 18:55:36 -05:00
test.mat remove unwraps, fix utf8 2024-02-29 21:05:10 -05:00
test.matc remove unwraps, fix utf8 2024-02-29 21:05:10 -05:00


matrix is a programming language, for use as a calculator, general math, and other scripting.

To compile and install matrix run cargo install --path ..


matrix contains 16 builtin types.

Type Description Examples
Nil Represents nothing (null) Nil
Bool Boolean type true or false true, false,
Int A 64bit signed integer 0, -13, 999
Float A 64bit floating point decimal 1.3, NaN, inf
Ratio A fratcional object consisting of two 64bit signed ints 1/3, 0/5, -3/8
Complex A complex number consisting of two 64bit floats 0+1i, 13-2i,
Regex A compiled regex string r'$test', r"test"
String A variable length string 'test', "test"
List A heterogeneous list [], [1 true],
Matrix A heterogeneous matrix with a domain and codomain [1 2;3 4], mat([1 2])
Table A heterogeneous table or map :{}, :{bees = 'bees'}
Function A compiled or builtin native function fn a (e) { e }, a = \e => e
Range A iterator from one Int to another Int 0..1, 10..=20
Iter A closed iterator object iter(<iterable>), once(<any>)
File A currently open file on the system file_open('test.txt', 'r')
Exception A error or exception thrown by the vm or the user throw(), throw(1,2,3)


All types are automatically considered true unless

  • Nil
  • Int, Float, Ratio, or Complex of value 0
  • Bool of value false
  • String of length 0

String Escapes

When writing strings (or regexies), these are the following escapes you can use

Escape Character
\\ Backslash
\0 Null Byte
\a Bell
\b Backspace
\t Horizontal Tab
\n Line Feed
\v Vertical Tab
\f Form Feed
\r Cariage Return
\e Escape
\x## Utf8 codepoint (single)
\u{##..} Utf8 codepoint (any size)


All matrix operators in order of high to low precedence from top down

Name Operator Associativity Examples
Field access left to right a.b
Function calls left to right a(), a(1, 2)
Negate, Not -, ! none (unary) -3, !a
Power ** right to left 3**4
Multiply, Divide, Modulo *, /, % left to right 2 * 3 / 4
Add, Subtract +, - left to right 1 + 2
Bitwise shift <<, >> left to right 13 << 2
Bitwise And & left to right a & 0xC3
Bitwise Xor ^ left to right 3 ^ 4
Bitwise Or | left to right b | 0xC3
Comparison ==, !=, <, >, <=, >= left to right a == b, c != d
And && left to right res && other
Or || left to right this || that
Range .., ..= left to right 1..2, 10..=20
Assign, OpAssign =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, **=, &&=, ||= right to left a = 3, i += 1

Variables and Scope

Unless running inside a REPL, all variables besides the standard library functions are locally scopped. Meaning they are only accessable from inside their scope, and will be deleted once that scope is left. If running in a REPL, all variables in the root scope will be globals.

Variables can be defiend though Assignment, Let, or Const. Assignment will overwrite if the variable already exists, or create if it doesnt. Let will only create a mutable variable. Cosnt will only create a immutable variable. If Let or Cosnt try to redefine a variable, an exception will be thrown.

a = 3; // a is 3
    println(a); // prints 3
    let a = 4;  // local a is 4
    println(a); // prints 4
    b = 3       // b is 3
println(b)  // undefined b, error
println(a); // prints 3
let a = 5;  // redefined a, error

Expression Control Flow

matrix is an expression based language, meaning everything is data, and everything is control flow. Every type of expression will always return a value, even if its Nil. You can assign functions to variables, blocks to tables, or function calls to lists.

The order of execution is always from left to right, unless when using a pipeline when its left to righ t for the pipeline and right to left to each pipeline component.

let a = {
    const bees = \a => a * 2;
} // a is 66

for i in 0..a { // prints 0 inclusive though 66 exclusive


matrix supports four types of loops, Loop, While, DoWhile, and For.

While and Loop are the same except Loop doesn't have a condition while While does. Both of these loops will check the condition first, then run the body if true. If false it will break the loop.

DoWhile is a backwards While, in which the body is run first, when the condition is checked.

For is the special out of the four since it takes an Iterator as an argument (see iterators). For will run the body until the Iterator stops (returns Nil).

while 1 {

loop {

do {
} while 1;

for i in 0..10 {


matrix supports a single function type, but with two seperate syntaxes. First you can create a normal function with the Function or Fn keywords, specify the name, optionally specify the paramaters, and then specify the function body. Second you can create a lambda function with the lambda syntax, which is the same except paramaters must be specified.

fn bees {}
fn bees a a
fn bees (a) a
fn bees (a,b) a+b

let bees = \=> {}
let bees = \a => a
let bees = \(a,b) => a + b

Partial Function Application

If you dont specify the full amount of paramaters to a function, instead of throwing an error, instead you get back a partial function call. This is another special function that takes in the remaining paramaters to the origonal function, and appends them to the inital paramaters.

let bees = \(a,b,c) => a+b*c;
let bees2 = bees(2)
let bees24 = bees2(4)
bees24(5) // is the same as bees(2,4,5)


Iterators are a special closed object in matrix that cannot be accessed or called. They can only be used inside forloops, pipelines, and the next std function.

Iterators will be called forever until they return a stop value, which in matrix is always Nil. This has the side effect of stopping iteration early if there is a Nil in the middle of your data, so do not let this happen.

Iterators must always be able to be called unlimited times, since its not gurenteed that after the first Nil, that it will never be called again.

To retrieve values from a iterator:

  • run it inside a for loop consuming the entire iterator
  • run it in a pipeline consuming an arbitrary amount of the iterator
  • run next(<iter>) to consime and return a single value from the iterator

Finally, many different types can be auto promoted to an iterator. These include List, Range, and Function. Lists will iterate over their elements. Ranges will iterate from the range start inclsive to the range end execlusive, stepping by 1. And functions will be called forever until they return Nil.


Pipelines are syntax sugar for nested function calls.

// is the same as
3 |> a |> b

The only difference is that each part of a pipeline is evaluated from right to left instead of left to right.

0..4 |> map(\a=>a**2) |> filter(\a=>a!=0) |> list // [1, 3, 9]


This project is licensed under the MIT License