src | ||
.gitignore | ||
Cargo.lock | ||
Cargo.toml | ||
README.md | ||
run.sh | ||
rustfmt.toml |
Persist
Warning
This project is in very early state of development, it is strictly unusable and you should not be expecting the project to ever produce a reliable product.
For now, this repository is released publicly in the hope that someone might find interest in the ideas and implementations of the project.
Description
A message oriented, dynamic, strongly typed scripting language with context serialization.
Messages
The program can be seen as a collection of loaded actors all awaiting messages to process. They can, in turn send messages to other actors.
This is like encapsulating function calls in serializable structures that are passed between objects.
Dynamic
Persistence is meant to introduce dynamic loading behaviour, and allows for easy hotloading of new objects or types.
Context serialization
The most distinct feature of persistence is that every object, including function logic is serializable. This allows the runtime to export a resumable snapshot of a session.
Examples
Objects
strictly everything is somehow an object with properties: functions, type declarations, modules...
/// type declaration
let Person = type{
name: string,
age: int,
};
/// Associating function is adding properties to the type
Person.new = fn(name: string, age: int): Person {
Person { name, age }
};
/// instructions can be ran in global scope
let bob = Person.new("bob", 25);
Signals
Signals are sent from one object to another.
/// Signal declaration
let Present = sig[]: string;
Person|>Present = fn(self) {
"my name is "
+ self.name
+ ", I am "
+ self.age
};
/// Sending a signal to an object
bob<|Present{};
Traits
Traits are sets of signal handlers.
let Human = trait[Present];
let Chocolatine = type[];
let GetName = sig[]: string;
let MakeChocolatine = sig(ammount: int): [Chocolatine];
/// Traits can be chained
let Baker = trait[GetName, MakeChocolatine];
/// you can define implementations on Traits
Baker|>Present[] = fn(self) {
"my name is " + self<|GetName() + ", I am a baker"
};
Modules
let a = {
let Tree = obj{
height: int
};
Tree.new = fn(height: int): Tree {
Tree { int }
};
let a_tree = Tree.new(5);
auto { Tree, a_tree }
};
/// re export
let Tree = a.Tree;
let b = {
let Measure = sig(): int;
Measure|>Tree = fn() {
self.height
};
auto { Measure }
};
/// append methods
a.Tree.get_height = fn(self) {
self.height
};
module exportation
let a = 4;
let b = "hello";
let add = fn(a: int, b: int): int a + b;
let serialized: string = export(auto { a, b, add });
let deserialized: Obj = import(serialized);
deserialized.add(19, deserialized.a);
primitive types
int
float
str
bool
Type<T>
Trait<I, O>
Trait
Obj<T>
Fn<I, O>
Arr<T>
considerations:
- move semantic ?
- shadowing ?
- expressions instead of statements ?
- type inference ?
- fn return inference ?
- references ? (gc)
- serialization ?
- algebraic types ?
- tuple ?