The GENESIS Script Language Interpreter (SLI) provides a framework in which a simulation programmer can define and manipulate GENESIS elements. The SLI interprets statements in the GENESIS simulation language, and constitutes the operating system ``shell'' at work when you are running GENESIS.
The simulator shell is an interpretive operating environment which lets you:
You can perform these operations in either of two ways:
User-defined SLI scripts are used to glue the pieces of a simulation together. XODUS graphical objects that you use to define the front end of a simulation and GENESIS data handlers are all controlled from SLI scripts.
The shell contains a library of basic commands which you can augment through the addition of compiled C commands or interpreted SLI functions.
GENESIS routines are called by entering a routine name followed by any necessary arguments and options separated by whitespace.
routine-name arg1 arg2 ... -option1 option1-arg1 ... -option2 ...
A valid routine-name is a script identifier consisting of any combination of alphabetic (A-Z or a-z) or numeric (0-9) characters, or underscores (``_'') -- all other symbols are invalid characters in an identifier.
Routine arguments consist of literal strings of characters, results of other GENESIS routines or expressions, strings of characters including whitespace enclosed in double quotes and the value of parameters passed to a script or function. Combinations of these which appear together without any intervening whitespace are concatenated and passed as a single argument to the routine.
Routine options follow command arguments, and are introduced by a dash character. Option names may be abbreviated to any unambiguous length. Each option may accept additional arguments following the option name.
A carriage return marks the end of a statement, so you do not need to use semicolons at the end of a line. However, you can use semicolons to terminate statements as a way to include multiple statements on a single line. Several examples:
genesis > reset; step 100 genesis > int a, b, c ; a=1 ; b=2 ; c=3 genesis > if( a < b); echo {a} is less than {b}; end 1 is less than 2In other cases, the ``command'' returns a value and might more properly be called a function. In the documentation for GENESIS commands, we will use the term ``routine'' for built-in GENESIS commands, and will reserve the term ``function'' for a script function that is written in the GENESIS scripting language. The procedure for creating your own functions is described under Functions.
The following two examples illustrate how a routine call can be supplied as the argument to another routine or as a value in a script language expression:
genesis > echo { getfield /neutral_test x } genesis > float length = { getfield /cell/soma len }
Routines used in the context of an argument to another routine or within a script language expression must be enclosed in curly brackets.
All GENESIS statements are subject to these and other basic syntactical rules. If a statement you submit violates these rules, the interpreter will respond with an error message (and ignore your instruction).
In GENESIS, you create a variable by entering a variable ``type'' specifier at the command line, followed by the variable name (a script identifier), optionally followed by a value to assign to the variable:
variable-type variable-name [= expression]You can create any of three types of variables at the GENESIS shell:
Type | Meaning | Example Value |
int | integer number | 5, 18, 6000, -34 |
float | double precision floating-point number | 5.0, 3.14, -2001.4 |
str | character string | five, 5.0, hello |
genesis > int a genesis > float PI = 3.141593 genesis > float myfloat = 2*PI genesis > float floatstr = "6.3" genesis > str hi = "hello there"Note that case is significant for variable names (as in other areas): ``PI'' is different from ``Pi'', which is different from ``pi''. Also note that the character sequence ``6.3'' could be the value of either a floating point variable or a string variable.
Once you have defined a variable, you can change its value using an assignment statement:
variable-name = expressionFor example:
genesis > a = 40 genesis > myfloat = a + 2*PI genesis > hi = "The value of myfloat = " @ myfloatNote that GENESIS does not have array variables. However, it has several objects that contain internal data structures that may be used as arrays. Further details are given in the documentation for Tables and Arrays.
Variables declared in a function are local to the function. Those declared outside of a function in a script (or script that is included with the ``include'' statement) are global variables. When a value is assigned to a global variable, it will affect any statements or functions that follow this assignment. One often refers to ``constants'' in a GENESIS script. These are not true constants, but are just variables thatare not expected to take on new values during the course of a simulation.
Good object-oriented programming style discourages the use of global variables. When possible, it is best to localize variables within functions, or to use oject fields to store values. However, it is often useful to use global variables in order to make them easily accessible throughout the simulation scripts. Scripts that create prototype channels (see Scripts/neurokit/prototypes) usually define global variables for ionic reversal potentials, and the cell reader ( readcell ) makes use of the global variables RM, CM, RA and EREST_ACT.
GENESIS provides the following routines for accessing global script variables.
Routine | Description |
addglobal | Declares a global variable; variable name may be a variable. |
getglobal | Returns global variable value; variable name may be a variable. |
listglobals | Lists currently defined global variables and functions. |
setglobal | Sets value of global variable; variable name may be a variable. |
Script variable values are retrieved by using the variable name in the context of an expression. Expressions are formed using variable names and operators in the usual way. (See Operators.) In some contexts, the value of a variable or an expression must be evaluated by by enclosing it in curly brackets in order to distinguish between the string of characters and the value represented by the character string. This is particularly true when the expression is to be evaluated as an argument of a GENESIS routine or script language function. (See Functions.)
The echo routine is useful for seeing how an expression will be evaluated:
genesis > float pi = 3.14159 genesis > float y genesis > y = pi/4 genesis > echo y y genesis > echo {y} 0.7853975 genesis > echo pi/4 pi/4 genesis > echo {pi/4} 0.7853975 genesis > echo {sin y} // WRONG! 0 genesis > echo {sin {y}} // CORRECT 0.7071063519
As with many languages, GENESIS will cast expressions involving both floating point and integer variables to floating point. It will also convert a string to a float if the string is a valid representation of a number. For example,
genesis > int i = 5 genesis > int j = 2 genesis > float x = 2 genesis > str num = "5" genesis > echo {i/j} 2 genesis > echo {i/x} 2.5 genesis > echo {num/2} 2.5 genesis > num = "i/x" genesis > echo {num} i/x genesis > echo {{num}/2} ** Error - CastToFloat: Error casting 'i/x', using 0.0 0
Often it is useful to use a string variable name to hold the name of a global variable. For example, one may want to pass the name of a global variable to a function that declares, sets, or retrieves the value of the variable. However, normal GENESIS syntax for declarations and assignments does not permit a variable a name to be specified by a string variable. The last three of the following GENESIS statements are illegal, and will produce error messages:
str name = "foo" float x float {name} // want "float foo" {name} = 5.5 // want "foo = 5.5" x = {{name}} // want "x = foo", or equivalently, "x = {foo}"The correct way to accomplish these results is to use the routines for accessing global script variables with the name of the global variable held in a string variable.
addglobal float {name} setglobal {name} 5.5 x = {getglobal {name}}
As with any programing language, GENESIS lets you define functions in order to make your script programs more modular and easier to modify. You should group function definitions together at the beginning of a script, preceding any statements that will use them. The listglobals routine will list any user-defined functions.
The general form of a function definition in GENESIS is:
function function-name [ (arg1 [, arg ... ] ) ] statement-1 . . . statement-n endFor example:
function print_area(length, diameter) float length, diameter float area float PI=3.14159 area = PI*diameter*length echo The area is {area} end function link_compartment(channel,compartment) addmsg {channel} {compartment} RAXIAL Ra previous_state addmsg {compartment} {channel} AXIAL previous_state end
The SLI also lets you define functions interactively at the GENESIS prompt. For example:
genesis > function my_echo(inputval) ? echo { inputval } ? end genesis > listglobals function my_echo genesis > my_echo 33 33
The return keyword allows a return from the function before the end statement. It may optionally be used to return a value. For example:
function make_positive(num) // a silly version of "abs" float num if (num >= 0) return {num} else return {abs {num}} end end
You are not allowed to define a function within another function. Normally, you cannot refer to a function in another function before it is defined. For example, the following script will produce an error message:
function func2 func1 "This is a test." end function func1(string) str string echo "The value of the string is: " {string} end func2
However, adding the line
extern func1
at the beginning of the script will give the desired result:
The value of the string is: This is a test.
The keywords function, return, end, and extern are features of the interpreter, not normal GENESIS commands; consequently, they do not appear in a listing of GENESIS routines (e.g., as given by the listcommands routine).
The routines argc and argv are often used inside of function definitions to return the number of arguments and the array of arguments which are passed to the function.
The table below lists the basic operators available in GENESIS, from highest to lowest precedence. These operators can be applied to variables or constants within a GENESIS expression.
Operators | Function |
- | unary minus |
** | power |
* / % ~ | multiply, divide, modulo (int only), bitwise complement |
+ - & | ^ @ | add, subtract, bitwise and, bitwise or, |
bitwise xor, string concatenation | |
! | logical complement |
< <= > >= == != | relational operators (perform both numeric |
and string comparisons) | |
&& || | logical and, logical or |
The following examples illustrate the use of several of the basic operators.
For string concatenation, the ``@'' operator is used:
genesis > echo {"sub" @ "genius"} subgeniusThe following command shows how precedence is employed:
genesis > echo { 24 / 12 + 7 * 2 } 16You can also explicitly specify the precedence of operations in an expression by using parentheses:
genesis > echo { 3 * 4 + 5 } 17 genesis > echo { 3 * (4 + 5 ) } 27The following command does not return 5.4 because each element of the expression is an integer:
genesis > echo { 9 * 3 / 5 } 5For comparisons in GENESIS, the integer 0 is considered False; all other integer values are considered True; GENESIS returns 1 to indicate True. The following command returns 1 because the expression is True (it would have returned 0 if the expression had been False):
genesis > echo { 4 > 2 } 1Here is an example of negation in determining the nonexistence of an element:
if (!{exists {dest}/soma}) ...The relational operators are defined to be non-associative. This prevents silly expressions like the following:
1 < 2 < 4 [WRONG]
GENESIS supports four kinds of conditional control structures:
Note that you can break out of any of these loops before their expected termination by using the ``break'' or ``return'' statements.
The GENESIS ``if ...'' conditional structure takes the following form:
if (expression) statements elif (expression) statements else statements endThe elif and else portions of the form are optional and multiple elif portions may appear.
The ``if''/``elif'' expressions are evaluated in the order of appearance. When an expression evaluates ``true'', all the statements between the ``true'' expression and the following matching ``elif'', ``else'' or ``end'' will be executed; if all evaluated expressions are ``false'', then the statements between the ``else'' and the ``end'' are executed (or no statements are executed if there is no ``else'' clause).
Note that the GENESIS if construct does not recognize the keyword ``then''.
These are some examples of valid if statements:
if(1) echo hello end if(1); echo hello; end if( (GRAPHICS == 1) || (5+3 > 10) ) echo hello endThe following function uses the if/elif/else/end construct and prints ``zero'', ``negative'' or ``positive'' depending on the first argument:
function iftest(arg) int arg if ( arg == 0 ) echo zero elif ( arg < 0 ) echo negative else echo positive end end
The GENESIS ``while ...'' conditional looping statement has the following syntax:
while (expression) statements endThe expression is evaluated. If it is ``true'' (i.e., not 0), then all the statements will be executed, then the expression will be evaluated again; if the evaluated expression is ``false'', then all the statements are skipped and control is turned to the first statement after the ``end''.
An example of a while loop is the following:
str parent while({getfield {parent} object->name} != "xgraph") parent = {el {parent}/..} endNote that the expression can be complicated and can involve some of the actual work of the loop.
The GENESIS ``for ...'' conditional structure uses an incrementable variable in assessing the condition for continuing through the loop. The syntax of the loop is as follows:
for (init_assignment; expression; incr_assignment) statements end
The init_assignment is an assignment statement which is evaluated once prior to entering the loop. The incr_assignment is an assignment statment which is executed following the statements each time through the loop. Otherwise, the for/end statement operates in the same manner as while/end.
To print the numbers one through ten:
int i for (i = 1; i <= 10; i = i + 1) echo {i} end
The GENESIS ``foreach'' statement loops through a set of statements once for each item in a specified argument list, having assigned the value of each item in the list to a looping variable for use by the statements:
foreach loop-var ( arg1 [ arg ...] ) statements endFor example:
str s str thingys = "foo bar baz" foreach s ({arglist {thingys}}) echo {s} endor
str name foreach name ({el {path}/##[OBJECT=xform]}) xshow {name} endThe use of wildcards in the specification of pathnames is described in the section Hierarchical Structure. Also see the documentation for arglist and el (``element list''). Note that in each of these examples, you need to have declared the variables used in the loop before their use in the loop.