303 lines
6.6 KiB
Markdown
303 lines
6.6 KiB
Markdown
# 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)
|
|
- [ ] Tail call optimization
|
|
- [ ] 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
|
|
```
|
|
|
|
### Set assignment
|
|
|
|
You can unpack a set by assigning it to another set, eg
|
|
|
|
```
|
|
[x,y] := [5,6]
|
|
|
|
print(x) # 5
|
|
print(y) # 6
|
|
```
|
|
|
|
The sets must have the same length, otherwise the expression will error.
|
|
|
|
This is useful for functions such as `head`
|
|
|
|
## 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
|
|
```
|
|
|
|
In order to avoid the system hanging you can use the `break` keyword to stop a loop.
|
|
|
|
```
|
|
x := 5
|
|
|
|
loop
|
|
if x = 0 then
|
|
break
|
|
end
|
|
|
|
x <- x-1
|
|
end
|
|
```
|
|
|
|
## Functions
|
|
|
|
Functions in openbirch allow you to define operations on a set of inputs. Functions are a first class type and can be defined as a set of arguments and a body.
|
|
|
|
`args -> body`
|
|
|
|
Heres a few examples:
|
|
|
|
```
|
|
# A function that takes 1 argument and returns the argument multiplied by 2
|
|
f := x -> x*2
|
|
|
|
f(4) # 8
|
|
```
|
|
|
|
If you want to use multiple arguments then supply a set as the argument
|
|
|
|
```
|
|
# A function that takes 2 arguments and adds them together
|
|
f := [x,y] -> x+y
|
|
|
|
f(2,3) # 5
|
|
```
|
|
|
|
Assigning a function to a name is the most common way of using them. This can be done in 2 ways
|
|
|
|
```
|
|
# Define f with a value that is a function
|
|
f := x -> x*2
|
|
|
|
# This does the same, but is more intuitive for people from a math background
|
|
f(x) := x*2
|
|
```
|
|
|
|
### Currying
|
|
|
|
Functions can return other functions. This creates a *closure*, that captures the variables passed to it.
|
|
|
|
```
|
|
add := x -> y -> x+y
|
|
|
|
add(2)(3) # this evaluates to 5
|
|
|
|
add2 := add(2) # This returns a closure where x is defined as 2
|
|
|
|
print(add2) # this prints ( (x: 2) => ([y] -> x+y))
|
|
# What this shows is a closure that captures "x: 2",
|
|
# where inside is another function that defines y
|
|
|
|
add2(5) # this is the same as add(2)(5) and returns 7.
|
|
```
|
|
|
|
### Built-in functions
|
|
|
|
A few functions are defined by default. They provide additional functionality
|
|
that has yet to be implemented into the language, such as syntax for indexing sets
|
|
and getting their length.
|
|
|
|
- `length(Set)` Returns the length of the given set
|
|
- `get(Set,Constant)` Returns the value at the given index in the set
|
|
- `head(Set)` Returns another Set consisting of `[head, [tail]]` where `head` is the first element in the set, and `tail` is all elements except the first element.
|
|
- `map(Function, Set)` Returns a new set where every value has had the function applied to it.
|
|
- `unset(String)` Undefines the given variable
|
|
- `set_float_precision(Constant)` Sets the number of bits used for numbers. Default is 128bits
|
|
- `get_float_precision(<optional Constant>)` Returns the current float precision. If a constant is given as the argument it will return the number of bits used for that constant.
|
|
|
|
# Running
|
|
|
|
## Linux
|
|
|
|
```sh
|
|
$ cargo run
|
|
```
|
|
|
|
### Nixos
|
|
|
|
```sh
|
|
$ 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`
|