An embeddable programming language somewhat resembling cellular processes.
- tokenising
- parsing
- semantic analysis and translation
- runtime system and host API
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.
Records are like "structs". 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)
The environment is a large unsorted set of records. 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 rules.
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 records freely.
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
expressstatement to add newrecords into the environment. For exampleexpress 3 Awill place 3 new "A"records into the environment. - the
callstatement used to communicate with the host application
rules can modify the environment by transforming a set of records into a new set of records.
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.
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));AGPLv3. Please see the LICENSE file.