RailScript

Complete current syntax

Keywords are shown in English. The editor can translate them to Dutch or German. Statements may be placed on one line or spread over several lines where the grammar is unambiguous.

Supported statements

StatementWhat it does
PARAMS TYPE name [, TYPE name …]Declare the script input parameters before its executable statements.
RETURNS TYPEDeclare the type of value this script returns with RETURN.
INT name = expressionDeclare a local whole-number variable. STRING and BOOLEAN work in the same way.
OBJECTTYPE name = domain["object"]Declare a strongly typed local reference to one existing namespace object.
name = expressionAssign a new value to an already declared local variable.
SET object.property = expressionWrite a writable namespace property.
LOG expressionWrite a value to the RailScript log.
IF condition THEN … ELSE … ENDExecute one of two branches; ELSE is optional.
WHEN condition UNTIL condition DO … ELSE … ENDWait for an event condition; UNTIL and ELSE are optional.
WHILE condition DO … ENDRepeat statements while a condition remains true.
FOR EACH item IN object[] DO … ENDIterate over a snapshot of an object collection.
WAIT millisecondsPause only this script for the specified duration.
PROMPT textPause this script and ask the user for confirmation.
PROMPT text, variableAsk the user for a value and store it in an existing variable.
MOVE train USING route [QUEUE]Start a saved route immediately or queue it.
MOVE train TO block [SAVEAS name]Generate a route to a destination block and optionally save it.
RUN "script" [WITH arguments]Start another enabled project script with optional parameters and continue immediately.
RUN THISRestart this script and complete the current execution immediately.
CALL "script" [WITH arguments]Start a script and asynchronously wait for completion; any returned value is ignored here.
TYPE result = CALL "script" [WITH arguments]Wait for a script and store the value supplied by RETURN.
RETURN expressionFinish the current called script and return its declared value.
RESERVE targets FOR trainAtomically reserve blocks, accessories or routes for a placed train.
RELEASE targets FOR trainAtomically release reservations belonging to a train.
SWITCH [commandStation] [PROTOCOL p] ADDRESS expression POSITION positionDirectly switch one decoder address; the defaults are DCC and the sole connected command station.

Comments

-- comment | // comment | # comment

Examples

-- comment
// comment
# comment

Local variables

INT name = expression | STRING name = expression | BOOLEAN name = expression | name = expression

Examples

INT count = 0
STRING message = "Ready"
BOOLEAN allowed = true
count = count + 1

Prompt the user

PROMPT text [, variable]

Examples

-- Confirmation only
PROMPT "Place the train on the programming track"

-- Store input in an existing local variable
INT speed = 40
PROMPT "Required speed?", speed

-- Or in an existing writable project variable
PROMPT "Driver name?", variable["driver"].value

Wait for an event, optionally with a limit

WHEN condition [UNTIL condition] DO statements [ELSE statements] END

Examples

WHEN feedback["K31"].occupied
UNTIL timer["limit"].expired
DO
    LOG "K31 became occupied"
ELSE
    LOG "Time limit expired"
END

Simple delay

WAIT milliseconds

Examples

WAIT 1500
WAIT timer["delay"].durationMillis

Switch a decoder address directly

SWITCH [commandStation] [PROTOCOL protocol] ADDRESS expression POSITION position

Examples

-- DCC on the sole connected command station
SWITCH ADDRESS accessory["Station signal"].address5 POSITION GREEN

-- Fully specified form
SWITCH commandStation["YaMoRC"] PROTOCOL MM ADDRESS 17 POSITION RED

Strongly typed object variables

OBJECTTYPE name = domain["name or GUID"]

Examples

BLOCK station = block["Platform 1"]
TRAIN intercity = train["IC 123"]
ROUTE journey = route["Station loop"]
ACCESSORY turnout = accessory["W12"]

SET station.maximumSpeed = 60
RESERVE station FOR intercity
MOVE intercity USING journey

An object variable refers to exactly one existing object for the duration of this script execution. Validation checks both the declared type and the type on the right-hand side of the equals sign. Available types are COMMANDSTATION, FEEDBACK, ACCESSORY, SIGNAL, SWITCH, BLOCK, TRAIN, WAGONGROUP, TRAINTYPE, LOCOMOTIVE, VARIABLE, ROUTE, SCRIPT, COUNTER and TIMER. COMMAND_STATION, WAGON_GROUP and TRAIN_TYPE are accepted as well.

Read and write namespace values

object.property | SET object.property = expression

Open the RailScript namespace reference

Examples

LOG feedback["K31"].occupied
SET counter["departures"].value = 1
SET accessory["A.1"].position = STRAIGHT
SET locomotive["Class 66"].speed = 64

Conditions and expressions

IF condition THEN statements [ELSE statements] END

Examples

IF feedback["K31"].occupied AND NOT block["Station"].reserved
THEN
    LOG "The route may be prepared"
ELSE
    LOG "Waiting"
END

-- Operators: + - * / = != < <= > >= AND OR NOT ( )

NULL and missing runtime values

expression = NULL | expression != NULL

Examples

IF train["Intercity"].currentRoute != NULL
THEN
    LOG "The train has an active route"
END

Parameters and return values

PARAMS TYPE name [, TYPE name …] | RETURNS TYPE | RETURN expression

Examples

-- This is the separate script 'Choose station block'
PARAMS BLOCK currentBlock, TRAIN train
RETURNS BLOCK
SET currentBlock.maximumSpeed = 50
RETURN currentBlock

When used, PARAMS belongs at the top; RETURNS is also part of the script header, directly after PARAMS or otherwise as the first declaration. Available types are INT, STRING, BOOLEAN, EVENT and every RailScript object type. Primitive values are copied. Objects are passed and returned as live GUID references, so changing an object through a parameter changes the real project object. Every execution path in a script with RETURNS must reach a matching RETURN.

Start scripts with RUN and CALL

RUN "script" [WITH arguments] | TYPE result = CALL "script" [WITH arguments] | CALL "script" [WITH arguments]

Examples

-- RUN starts the script and continues immediately
RUN "Announce departure" WITH train["Intercity"]

-- CALL waits and stores the BLOCK return value here
BLOCK chosen = CALL "Choose station block" WITH block["Platform 1"], train["Intercity"]
LOG chosen.name

-- A standalone CALL may ignore the returned value
CALL "Check station" WITH chosen

-- Nothing below RUN THIS is executed
RUN THIS

RUN is fire-and-forget: the called script starts with the supplied parameters while the caller continues. CALL waits for RETURN without blocking the user interface, so WAIT, WHEN and PROMPT remain asynchronous inside a called script as well. CALL chains are limited to 32 levels. Running and waiting scripts are visible in the Script Monitor and their execution is written to Script Logging; enable Debug there for statement-level logging.

Warning: scripts can start other scripts and restart themselves. Uncontrolled or very frequent starts can create so many concurrent executions that RailKernel, or even the entire system, becomes unresponsive. Keeping such constructions bounded and manageable is the user’s responsibility.

The event parameter

PARAMS EVENT event

Examples

-- RailKernel supplies this automatically when an object event starts the script
PARAMS EVENT event
LOG event.type + " from " + event.objectType + " " + event.objectName
IF event.trainName != NULL
THEN
    LOG "Train: " + event.trainName
END

The parameter name is your choice. With PARAMS EVENT trigger, for example, the same script uses trigger.type and trigger.objectName. The existing implicit event.* values remain available for older scripts.

React to every train feedback

WHEN condition DO statements END

Examples

WHILE train["Intercity"].currentRoute != NULL
DO
    WHEN train["Intercity"].newFeedback
    DO
        SET train["Intercity"].function[3].active = true
        WAIT 500
        SET train["Intercity"].function[3].active = false
    END
END

Loop

WHILE condition DO statements END

Examples

INT step = 0
WHILE step < 10
DO
    step = step + 1
END

Collections and FOR EACH

FOR EACH item IN object[] DO statements END

Examples

INT occupied = 0
FOR EACH item IN block[]
DO
    IF item.occupied
    THEN
        occupied = occupied + 1
        LOG item.name + " is occupied"
    END
END
LOG "Occupied blocks: " + occupied

Script logging

LOG expression

Examples

LOG "Train speed: " + locomotive["Class 66"].speed

Start or queue a saved route

MOVE train USING route [QUEUE]

Examples

MOVE "Intercity" USING "Station loop"
MOVE "Intercity" USING "Station loop" QUEUE

Generate a route to a destination block

MOVE train TO block [SAVEAS "route name"]

Examples

-- Generate and execute a temporary route
MOVE train["Intercity"] TO block["Platform 4"]

-- Save the generated route as well
MOVE "Intercity" TO "Platform 4" SAVEAS "Intercity to platform 4"

-- Names without spaces may be written without quotes
MOVE Intercity TO Platform4

Reserve and release railway resources

RESERVE targets FOR train | RELEASE targets FOR train

Examples

-- Reserve one or more resources atomically for a placed train
RESERVE block["Platform 1"], accessory["A.1"] FOR train["Intercity"]

-- A block, accessory or complete route may be reserved
BOOLEAN acquired = RESERVE route["Station loop"] FOR train["Intercity"]
IF acquired
THEN
    LOG "Route reserved"
END

-- Release the same resources; RELEASE also returns BOOLEAN
BOOLEAN released = RELEASE route["Station loop"] FOR train["Intercity"]

Object selectors

domain["name or GUID"].property

Examples

feedback["K31"].occupied
feedback["object-guid"].occupied
locomotive["Class 66"].function[0].name

Value rules

  • Object names and GUIDs are both accepted as selectors.
  • Text uses double quotes; supported escapes include \n, \r, \t, \" and \\.
  • Numbers may be integers or decimals. INT local variables require whole-number values.
  • Boolean literals are true and false. Enum values such as STRAIGHT are written without quotes.
  • SET is required for namespace attributes; local variables are assigned without SET.
  • A script failure is recorded in RailScript logging and in the Script Monitor.
  • NULL represents a value that is currently absent, such as currentRoute when a train has no active route.
  • The ! operator is a compact equivalent of NOT.
  • PROMPT accepts BOOLEAN, STRING and INT variables. BOOLEAN uses a TRUE/FALSE list; INT accepts whole numbers only. Cancelling the dialog cancels the waiting script.