boros
(Shortened from Ouroboros) is a language that allows you to write self-modifying programs.
It was developed during the 2021 Lang Jam. The theme of the hackathon was first-class comments
.
boros
is a strict, impure, dynamically-typed functional language with ML-inspired syntax.
The entire boros
script file is one big expression, which is evaluated and printed by the interpreter. (If it evaluates to ()
, called unit, then nothing is printed)
Variables and functions are declared with let
, and multiple mutually-recursive functions can be declared with let ... and
.
Here's a simple factorial program:
let fact x =
if not x then
1
else
x * fact (x - 1)
in
let n = 10 in
fact n
Values in boros
are immutable, with the exception of lists and records.
Here's how to define and use them:
let l = [1, 2, 3] in
l.[0] <- "abc";
print l.[0];
let r = { x = 2, y = 3 } in
r.x <- r.x + 1;
r.z <- 4; {- "You can even add new fields to an existing record!"; -}
In boros
, comments are interpreted as part of the source code. (Can't get more first-class than that, right?)
Furthermore, all comments are accessible (in text form) from within boros
scripts via a mutable global list called comments
.
When the script terminates, the comments are replaced with the new strings from the comments
list, and the script is re-run. This continues until either the script stops modifying the comments, explicitly calls the halt ()
function, or an exception is thrown.
A good example of this can be found in the Fibonacci example.
Comments are delimited by {-
and -}
. Currently, there's no support for line comments or nested comments.
Scripts can also have a shebang (#!
) on the first line, which is ignored by the interpreter, and is not accessible from within the script.
{- "Safe division"; -}
let (/?) a b =
if b == 0 then
0
else
a / b
in
2 /? 0
let add = x y -> x + y
in add 2 3
{- "Same as the following:"; -}
let add x y = x + y
in add 2 3
let add = (+)
in add 2 3
a; b
will evaluate a
and ignore its result, then evaluate and return b
. This can be used to sequence (usually side-effectul) expressions.
print 3;
a.[0].x <- 2;
factorial 100
boros
is dynamically-typed. Performing operations on values of the wrong type will halt the program with a Runtime error
.
You can use the type
function to get the "approximate" type of a value, e.g. type 2 == "Num"
, type [1, "abc"] == "List"
.
You can also throw exceptions using the throw
function. Any value can be provided as parameter, and will be show
n in the error message. There is currently no catch
/finally
mechanism.
This repo also includes a VS Code extension for syntax highlighting.
You can install it by running the install-vscode-ext.sh
script.
- GHC (>= 9.0.1)
- cabal (>= 3.6)
(Can be installed via ghcup)
cabal build
cabal run . <script file> <args for boros script>
If not already built, cabal run
will also build the project.
e.g.
cabal run . Examples/Factorial.brs 100
This repository is licensed under the terms of the GNU General Public License v3.
For more details, see the license file.