4 KiB
Openbirch Rust
Openbirch rewritten in rust.
Very messy and bad, im gonna start the umpteenth rewrite soon.
Features
[x] Constants (numbers)
[x] Addition
[x] Subtraction
[x] Multiplication
[x] Division
[x] Arbitrary float precision
[ ] Sets (or lists, arrays, etc)
[x] Definition
[x] Multiplication with constants
[x] Concattenation
[ ] Index operator
[x] Functions
[x] Native functions
[x] User defined functions
[x] Currying
[x] Closures
[x] Calling
[x] Scopes
[x] Shadowing variables
[ ] Ranges
[x] Defining ranges (1..5
is a range of [1..5)
)
[ ] Iterating ranges
[x] Evaluating ranges (very hacky, but defining a Set of length 1 with a range expands said range into the set, eg [1..3]
becomes [1,2]
)
[ ] Loops
[x] Infinite loops (loop ... end
block)
[ ] For loops (for x in y ... end
block)
[x] Break keyword
[ ] Match expression
[x] If expression
[x] If expression
[x] If-else expression
Wanted
[ ] More concise syntax, i dont like how it is right now [ ] Fix stack overflow with recursive functions (internally convert to loops) [ ] Generally implement more [ ] Implicit multiplication (may not be possible to implement non-ambiguously) [ ] Differentiation [ ] Integration [ ] Better error handling (i was lazy and skimped on errors, bad move)
Syntax
Every Openbirch program is made up of 0 or more expressions.
An expression is anything from a binary operation like 2+2
to function calls f(x)
and
even assignments x := 5
.
All expressions return a value. For expressions that "dont" they return an Empty
, which cant
be used for anything and will error if used in other operations (eg. 2+{Empty}
).
Definition
Variables can be defined with a define
expression.
x := 5 # define x as 5
print(x+x) # prints 10
As openbirch is a symbolic language variables can be used before assignment
y := x^2
print(y) # prints x^2
x := 5
print(y) # prints 25
Scopes
Some expressions define a scope, where all defined variables inside will be deleted once the scope ends.
Expressions that create a scope include, but are not limited to,
- If-else
- Loop
- Functions
- Closures
If a variable is defined outside a scope it will be shadowed inside the scope. What this means is that inside the scope the variable will have the shadowed value, while outside the scope it will have the previous value.
x := 5 # Global scope
print(x) # prints 5
if true then # Define a new scope
x := 5000 # Shadow the value of x
print(x) # prints 5000
end # Scope ends here
print(x) # prints 5
Assignment
Since you may want to change the value of a variable outside the current scope you can use an assignment
rather than a definition.
x := 5
if true then
x <- 500 # Assign to x rather than defining it and shadowing it
end
print(x) # prints 500
If-else
If expressions are defined as such
if {condition} then
# 0 or more statements
end
and if-else as
if {condition} then
# 0 or more statements
else
{expression}
end
Since if
is an expression the body of the else branch can be another if expression, in which
case only 1 end
keyword is needed.
if {condition} then
# 0 or more statements
else if {condition} then
# 0 or more statements
end
Since all expressions evaluate to a value the value of the if expression is the resulting value of the last statement in the chosen branch, eg.
x := if true then
# Evaluate some expressions
2+2
f(x)
y := f(f(x))
# Last expression is returned
5
else
0
end
print(x) # prints 5
if a branch is empty then Empty
is returned.
Loops
Currently the only type of loop is an infinite loop.
loop
# This will repeat forever
end
Running
Linux
$ cargo run
Nixos
$ nix develop
$ cargo run
Windows
idfk, havent used that shit in years, but probably just cargo run
.
MacOS
never used, but again probably cargo run