cytosol
An embeddable programming language somewhat resembling cellular processes.
State of the implementation
- tokenising
- parsing
- semantic analysis and translation
- runtime system and host API
Overview of the language
Records in the environment can activate gene functions or trigger rules. Gene functions can express new records into the environment. Rules can modify the records in the environment.
record
s
Records are like "struct
s". They have a name and can have fields.
record PersonInfo(name: string, age: int)
In expressions, fields of records can be accessed with their name, such as p.name
or p.age
.
The name of a record can be used as a type.
record Student(final_grade: int, info: PersonInfo)
Environment
The environment is a large unsorted set of record
s. Records can be added or removed from the environment.
To check or bind to a record in the environment they need to be in the "execution factor" list of gene
functions or in the "reactant list" of rule
s.
A cytosol
program can only add new things into the environment by using the express
statement in gene
functions.
The "host application" that manages the execution of cytosol
program can also inject or remove record
s freely.
gene
functions
gene
functions are nameless functions with an "execution factor" list and a "body".
gene [2 A, 4 B, 0 C]
{
express 10 D
}
The execution factor list is enclosed by [
and ]
. An execution factor is a record
that is required to be in the "environment". Only when all execution factors are met/available will the body of the gene
function run.
A number in front of the name of a record
signifies the quantity that needs to be available in the environment. The quantity 0
means that the record
must not be present in order to run the body of the gene
function.
An execution factor can be bound to a variable by using name: TypeName
. This will bind 1 record
to the variable name.
The body can contain a list of a statement, which at the moment can only be
- the
express
statement to add newrecord
s into the environment. For exampleexpress 3 A
will place 3 new "A
"record
s into the environment. - the
call
statement used to communicate with the host application
rule
s
rule
s can modify the environment by transforming a set of record
s into a new set of record
s.
A rule
has a "reactant list", which states the part of the environment needing to be present for the rule
to perform its function.
With all the reactants available the "product list" will be inserted into the environment and all the reactants will be removed.
rule [4 Hydrogen, 2 Oxygen] -> 2 Water
Just like with the "execution factor list" of gene
functions, reactants can have a quantity or be bound to a variable name.
Similarly to the express
statement, the product list can also contain quantities.
extern
functions
With the extern
keyword a function can be declared that can be called from within gene
function with the call
statement.
extern print_line(s: string)
// Similar to a "main" function.
//
// This expects the `Start` record to be inserted by the host
// application in order to run this gene function.
//
// The `StartInhibitor` is used to make this gene function
// run only once.
gene [Start, 0 StartInhibitor]
{
call print_line(s: "hello world")
express StartInhibitor
}
record Start
record StartInhibitor
Implementations for extern
functions can be provided through the ProgramContext
of the DriverExecutionState
.
let mut exec_state = DriverExecutionState::default();
let ctx = exec_state.program_context();
ctx.set_extern_function("print_line", |s: String| println!("{}", s);
ctx.set_extern_function("print_string", |s: String| print!("{}", s);
ctx.set_extern_function("print_int", |i: isize| print!("{}", i));
License
AGPLv3. Please see the LICENSE file.