FramScript language 

The FramScript syntax and semantics is very similar to JavaScript, JAVA, C, C++, PHP, etc. In FramScript,

  • all variables are untyped and declared using "var" or "global" statements
  • functions are defined with the "function" statement
  • references can be used for existing objects
  • no structures and no pointers can be declared
  • there is the Vector object which handles dynamic arrays
  • FramScript code can access Framsticks object fields as "Object.field"

Before execution by FVM (Framsticks Virtual Machine), FramScript source code is first translated to FVM assembler source code, and then transformed to FVM machine code. Scripting is a powerful instrument and lets an advanced user control the Framsticks environment and use it according to their needs. However, error reporting while processing scripts is not perfect: if a script is erroneous, do not expect the translator to always precisely locate the bug.

Statements

(brackets [] denote optional parts)

if (expression) statement; [else statement;]
for (expression;expression;expression) statement
while (expression) statement;
do statement; while (expression);
switch(expression) { case constant: statements... default: statements... }
{ statement; [statement;] }
return [expression];
break [level];
continue [level];
label_name:
goto labelname[:];
var name[=expression][,name2[=expression2]][...];
function name([parameter_names]) {statements}
@include "filename"
asm { source code for FVM }

Remarks:

  • "level" is a positive integer specifying the loop you want to "continue" or "break". "break 1;" is equivalent to "break;", "break 2;" refers to the loop containing the innermost loop, and so on.
  • "goto" can be dangerous is some cases (like variable declarations jumped over), so it is recommended to avoid it.

Variables

Variables must be declared before they are used. Unlike in C, the declaration does not specify the variable type.

Variables are untyped, but the values are typed. The value can be of one of 5 types: integer, floating point, string, object reference or the special empty value (null).

Some operators act differently depending on the value type.

Example:

var int=123, float=1.23, string="123";
int+=0.0001;     // result = 123
float+=0.0001;   // result = 1.2301
string+=0.0001;  // result = "1230.0001"

That's why sometimes you will need to use constructs like ""+float or 0+string, in order to explicitly force type conversion. Note that the result may be of different type depending on the order of variables (int+string will be integer, float+int will be floating point, int+float will be integer, etc.). Consequently, float+" "+int will produce a single floating point value, whereas ""+float+" "+int will produce a string of two values separated by a space char.

Global variables are declared using the "global" statement. Unlike the local ("var") variables, globals preserve their values between FramScript calls. This is useful when a function is called from outside the code module, as it happens in experiment definitions, styles, neurons and user scripts.

Example:

global counter;
function eventHandler()
{ counter=1+counter; }

function getCount()
{ return ""+counter; }

Expressions

Most of the C language expressions are also valid in FramScript. This includes arithmetic and logical operators, parentheses, function calls, and assignments. Moreover, the following FramScript specific opearator are available:

  • "typeof" expression – determine the expression value type. The return value should be interpreted as follows:
    • 0 = empty (null)
    • 1 = integer
    • 2 = floating point
    • 3 = string
    • "classname" = object of class "classname". Thus typeof typeof expression is equal to 3 if and only if the expression returns object reference
  • "." (dot) – member access operator (like in C++). It can be applied to any expressions containing object references, or to the special static object names. Static object names are equal to the class names shown in the Class Navigator, e.g.:
    var expdefname=Simulator.expdef;   // access object field
    Simulator.load("experiment.expt"); // invoke object method
    var two=Math.sqrt(4);              // invoke object function
    
    There is only one "static object" for each class. Some objects usually have a single instance and are accessed using this method (like the Simulator or Math in the example above).
    Multiple objects of the same class are accessed indirectly with using object references:
    var g=LiveLibrary.getGroup(0);           // get the reference
    var info="This group is called "+g.name; // use the reference
    
    Sometimes, the static object is used to create more objects:
    var v=Vector.new();           // static object creates a dynamic object
    v.add(123);                   // the reference is used
    var s=v.size;
    
    The special syntax "Object.Class:Member" can be used to provide the class name of the object in cases where it cannot be determined by the compiler from the object expression. If you know programming – this is similar to casting. This syntax is generally used by advanced programmers as an additional hint:
    var c=...some...creature...;
    c.movve(1,2,3); // this typo will only be detected at runtime
                    // (the compiler does not know the class name, so it does not try to check the member name)
    c.Creature:movve(1,2,3); // but this syntax results in a compilation error
                             // (we tell the compiler that "c" is of type "Creature")
    
    "ClassName.*" can be used as a reference to the special static object if it has to be passed to some function:
    var v=callNew(Vector.*);
    var d=callNew(Dictionary.*);
    
    function callNew(obj)
    {return obj.new();}
    
  • ".[expr]" – indirect member access operator. Works like the regular "dot" operator but the member name is passed as an expression:
    var which=2;
    var value=Genotype.["user"+which]; // works like Genotype.user2
    
  • [] – vector operator (vector is a simple array-like object)
    The [] operator can be used in two ways:
    • [ expr1, expr2, ... ] – vector creation expression. It is a short form of:
      v=Vector.new(); v.add(expr1); v.add(expr2); ...
      
    • object [ expr ] – "get" access operator. Works the same as object.get(expr). Thus you can access a Vector object like a regular array in C:
      var v=["one","two","three"];
      var third=v[2];         // == v.get(2)
      var d=Dictionary.new();
      d.set("name","value");
      var value=d["name"];    // works for any object implementing the "get" method
      
    Note that "object [ expr ] = expression" will not work, because [] acts as "get". You need to use "set" explicitly to alter the vector object.
    var v=[];                // empty vector
    v.set(10,"10th value");  // v.set(...) will expand the vector when required
    
    Note 2: See the difference between the "get" operator "[]" and the indirect member access operator ".[]"
    var d=Dictionary.new();
    d.set("size",123);
    var v1=d["size"]; // ==123 - equivalent of d.get("size"), gets the previously set value
    var v2=d.["size"]; // ==1 - equivalent of d.size, gets the object field value
    
  • function FUNCTIONNAME – creates the function reference.
  • call (FUNCTIONREF)([arguments,...]) – invokes the function using the function reference obtainad from the "function" operator:
    var calltable=[function one,function two,function three];
    var selector=1;
    var fun=calltable[selector];
    var result=call(fun)(argument1,argument2); // function two will be called
    

Functions

Functions are defined as follows:

function name([parameter_names]) {statements}

All parameters are passed by value (copied). However, an argument (or a return value) can contain object reference, in which case it is the reference that is actually copied.

A function can return a value to the caller using the "return expression;" statement. If a bare "return;" is used, the return value is undefined.

Example:

function factorial(n)
{
    if (n<3) return n;
    return factorial(n-1)*n;
}

Functions can also have multiple names, which is useful when you need many functions with an identical body – for example:

function onLeftClick,onMiddleClick,onRightClick(x,y)
{
  //do something...
}

Using Framsticks classes, methods, and variables

See FramScript reference to learn about internal Framsticks classes, methods, and variables. You can also use the class browser (available both in GUI and command-line interfaces).

 
 
 
On the forum: