An expression based interpreted language
Files can be evaluated, and return a result - this is a “module system”. Data types are: bool, double, string, symbol, function, list, dict
true, false, “string”, $symbol,
where the next term is the body of the function.
A list is defined as [1, 2, 3, 4] A dict is defined as <a: b, c: d>
{} <- introduces a new scope () <- doesn’t introduce a new scope The result of these blocks is either the last value, or nil if empty Expressions are separated inside the blocks with ;
A value can be assigned with “let”:
let x 2, y 3, z 4 multiple assignments can be done in a let statement, with the last one being the final result
Recursive assignment, where the expression being assigned to a variable has access to that variable can be defined with letrec fac |n| n `+ (fac n `- 1)
Functions are called by a symbol, then arguments: myfun 1 2 arg3
They are curried if less than the required number of arguments is given
Functions can be called infix by prepending with `: The sum function takes two things: + 2 3 = 5 This can be made infix with: 2 `+ 3 = 5
extract a b c d e : dict
This binds the given symbols to the corresponding values of those symbols in the dictionary
{let d {a: 2}; $a d = 2} (or, with infix: d`$a = 2 )
cond { a ~ 3; b ~ 4; else 5 }
f x y! Should mean f x (y!)
f x `* y should mean f (* x y)
f x! `* y should mean f (* (x!) y)
(f `g) `h should mean h(g(f))
Mutable values can be stored in a box, denoted with &value @dereferences the value
Can pass down a context to the child. This is just a dict of symbols to values. Just like parameters in scheme
start a context expression with a “with”: Takes in the dictionary argument, which it merges with the above dict
Values inside the expression (dynamically, not lexically) can access the context with ^$a, ^$b, which access values belonging to the context.
with <$a: 2, $b: 3> { cond {let x %a => x, else 3} }
s
x, y | a b! |
- [X] Modify tail calls to recursive functions use the same stack frame?? (maybe not reasonable)
- [ ] Add in a trait system (similar to rust/elixir behaviours)
- [X] Add in native function calls (sum and stuff)
- [ ] Add a module system Not totally sure how to do it yet. Have static modules and computed modules. A static module is like a struct - all things have their positions at compile time. Computed modules aren’t static, so they are a little slower to access, but dynamic
- [ ] Add in structured coroutines Maybe do this in a way similar to kotlin, run by default in a tokio thread pool. Don’t have explicit await/async, just colour functions. Async functions can only be run inside other async functions or launch {} block. Normal functions can be run anywhere.
- [X] Update expressions so that they can be given a register to put their result into When compiling an expression, give an optional register to put the result into. This register is not managed by the expression - it’s managed by whatever called the compilation of it. It doesn’t need to do anything to this slot. (Use the Local::Reserved struct from outside for this)
- [X] Make all frames share the same underlying buffer, each one should have an index