A general-purpose multi-paradigm language, that aims to provide a scripting language with powerful concurrency and simple syntax.
Why it must exist? Most scripting languages usually have very limited concurrency support, if any, are too noisy syntax or too minimalistic and fail domain completeness. This experiment aims to fill those gaps and provide new ideas for scripting language design.
These are the principles that guided the design of miniUni:
- 🌐 Everything is an expression.
- 🚫 No explicit or implicit null value by default.
- ⚡ Powerful concurrency: structured concurrency and async programming primitives
- 🛠️ Effect handlers for powerful dependency injection and control of side effects
- ✍️ Flexible but minimalistic syntax, formatting friendly and minimizing indentation.
- 👐 Keep design unopinionated.
- 🔗 Keep design complete over the whole domain: make reasonable semantics for every possible feature input.
Download single executable interpreter for your platform from releases. All commands expected to be executed from the location of the download.
To run programs do the following:
./miniUni run <file>
Or start REPL for interactive command-line usage:
./miniUni repl
Install syntax highlighting for vscode:
code --install-extension ./miniuni-highlight.vsix
And start writing your first script.
Create a hello_world.uni
file and paste in:
print "Hello world!"
Then pass it to the interpreter to run:
./miniUni run hello_world.uni
And behold, the output:
Hello world!
You can also use REPL:
./miniUni repl
And paste commands you wish to execute:
>> print "Hello world!";
Hello world!
>>
Syntax is a mix of functional and C-like syntax, so if you are coming from one of such languages (rust, haskell, js, elixir) it may look familiar to you For a more complete set of examples and whats possible, check out the examples and tests suites, but here is an overview of the syntax:
- Comments
// comment
,/* block comment */
- Values
- String and number literals
"string"
,1234
,1.2
- Symbols
symbol()
- Channels
channel()
- Atoms
:atom
- String and number literals
- Variable
mut x := 1
,x := 1
- Assignment
x = 2
,x.y = 123
- Arithmetic
- Add, subtract, multiply, divide
(1 + 2) * 3 / 5 - 6
- Exponentiation and modulo
2 ^ 8
,28 % 12
- Increment decrement
++x, --x
,x++, x--
- Increment-assign
x += 1
- Add, subtract, multiply, divide
- Boolean logic
- Boolean and, or and negation
x and y or not z
- Comparison
x < 3 or x > 2 or x <= 4 or x >= 6
- Equality and deep equality
x == 1 and x != 2
,x === 1, 2 and x !== 2, 4
- Pattern matching
x is (a, b) and a == b + 1
- In operator
key in (x: 1, y: 2)
- Boolean and, or and negation
- Data structures
- Tuple
1, 2
,x[0]
- Record
first: 1, second: 2
,x.first
- Dictionary
["a"]: 1, ["b"]: 2
,x["a"]
- Tuple
- Loops
- For loop
for x in y { print x }
- While loop
while x != 0 do x--
- Loop
loop print "infinity and beyond"
- For loop
- Branches
- If branching
if x != 0 { print "in branch" }
- Match
switch x { 1 -> "x is 1", _ -> "x is not 1" }
- If branching
- Code blocks
y := { x:= 1; x + 1 }; print "x is not visible here"
- Functions
- Function literal
fn x, y do x + y
- Function call
f x y
- Pipe
x |> f |> g
- passes value tof
and then result passed tog
- Lazy blocks
f { x }
- blocks are implicitly converted to functions (equivalent tof fn { x }
)
- Function literal
- Concurrency
- async/await
async f x
,await x
- Parallel composition
1 | 2
- execute expressions in parallel - Channels
c <- 1
,<- c
- async/await
- Pattern matching
- Tuple pattern
x is (a, ...b, c)
- Record pattern
x is { a, b }
- Tuple pattern
- 3 forms for specifying body of a construct (function,
for
andwhile
loops,if
branching)fn x { y }
- explicit code blockfn x do y
- implicit block until newline or semicolonfn x -> y
- implicit block until the end current grouping (block, parens, square brackets)
- Effect handlers
inject a: 1 { ... }
- injects value1
asa
inject [return_handler]: fn x { ... }
- handler to be called when no other effect is performedmask :a { ... }
- masks effecta
(will forward handling to the next one)without :a { ... }
- forbids effecta
handle (:a) x
- handles effecta
with valuex
handler fn (callback, value) { ... }
- creates a handler with explicit callback
The project's scope is already fixed, so it is not accepting any feature requests, only bug fixes and documentation.
Repo is using bun as a build tool, but works just as well with node. At least one of them should already be installed on your machine. To pull repo and start developing do the following:
git clone git@github.com:gidra5/miniUni.git
cd miniUni
npm i
npm run watch
This will start vitest
in watch mode to automatically run test suits and show the results in terminal and browser.