Skip to content

Language Guide

Mick edited this page Jul 7, 2026 · 7 revisions

Language Guide

This guide documents RuleScript language behavior for the current stable v1.10.0 line.

Basic Syntax

  • Identifiers and function names are case-sensitive.
  • Simple statements end with ;.
  • Block headers end with :.
  • end can close most blocks; dedicated endings such as endif, endfunction, endtask, and endparallel remain valid.
  • // starts a single-line comment.
  • /* ... */ creates a multi-line comment.
  • /// creates documentation metadata for the next function.
  • #region and #endregion create editor folding regions.
// A comment
var distance = 519;
result = distance + 1;

Values

RuleScript supports:

Value Example
number 10, 2.5, -3
string "RuleScript", "Line 1\nLine 2"
boolean true, false
null null
array [1, "two", true]
object { Status: "OK", Position: { X: 519 } }

Strings use double quotes. Supported escapes are \", \\, \n, \r, and \t.

Arrays are mutable list values. Indexes are zero-based and must be whole-number values within bounds.

Object properties can be read from dictionaries, read-only dictionaries, object literals, JSON values, and public C# object properties:

var robot = { status: "OK", position: { x: 519 } };
var status = robot.status;
var x = robot.position.x;

value?.property returns null when the receiver is null. Missing properties and null member access without ?. are runtime errors.

Variables and Assignment

var distance = 519;
var result;
const threshold = 500;

distance = distance + 1;
result = distance > threshold;

const creates a read-only binding. Assignments can target variables, array elements, object members, nested targets, mutable dictionaries, and writable host-object properties:

var robot = { position: { x: 0 }, samples: [1, 2] };
robot.position.x = 519;
robot.samples[0] = 42;

Destructuring declares multiple variables:

var [first, second] = [10, 20];
var { name, enabled } = { name: "RuleScript", enabled: true };

Top-level variables live in RuntimeContext. Inside a function, normal assignments write to local scope. Use global.name for explicit shared context access:

var count = 0;

function Increment() -> void:
    global.count = global.count + 1;
    return;
endfunction

Operators

From highest to lowest precedence:

Precedence Operators
1 ()
2 !, unary -
3 *, /, %
4 +, -
5 >, >=, <, <=
6 ==, !=
7 and
8 or
9 ??

+ performs numeric addition when both operands are numbers and string concatenation when either side is a string. and, or, and ! require boolean operands. left ?? right evaluates the right side only when the left side is null.

Control Flow

if distance > 500 then:
    result = "NG";
elseif distance == 500 then:
    result = "EDGE";
else:
    result = "OK";
endif
switch status:
    case "ok":
        result = "Continue";
    case "warning", "error" when retryCount <= 3:
        result = "Inspect";
    case null:
        result = "Missing";
    default:
        result = "Unknown";
endswitch

switch selects the first matching case and does not fall through. default is optional but analysis reports a warning when omitted.

Loops

var i = 0;

while i < 5:
    i = i + 1;
endwhile
foreach item in [1, 2, 3]:
    if item == 2 then:
        continue;
    endif

    if item > 10 then:
        break;
    endif
endforeach

foreach supports lists, arrays, IEnumerable<object?>, and strings. break and continue apply to the nearest loop.

Functions

Functions are declared at top level. v1.10.0 supports both classic untyped functions and strongly typed signatures.

function Add(left: number, right: number) -> number:
    return left + right;
endfunction

function Log(message: string) -> void:
    Print(message);
    return;
endfunction

Supported type names are any, null, number, string, bool, boolean, array, object, and void.

Rules:

  • Parameters and var declarations are local.
  • return expression; returns a value.
  • return; returns null and is required for void functions that return explicitly.
  • A non-void typed function must return a compatible value on every path.
  • Overloads may share a name when parameter signatures differ.
  • Return type does not participate in overload resolution.
  • Recursion is intentionally blocked.

Imports and Modules

import "common";
import "robot" as robot;

result = Shared();
status = robot.GetStatus();

Imports are top-level only. Extensionless paths use RuleScriptEngine.ScriptFileExtension, .rules by default. Imported files may contain imports and declarations, but not top-level executable statements.

Use export function and export const to define a module's public surface:

export const DefaultLimit = 500;

export function IsHigh(value: number) -> bool:
    return value > DefaultLimit;
endfunction

Once a module contains any explicit export, unmarked declarations are private.

Parallel Tasks

A parallel expression returns task results in declaration order:

var values = parallel:
    task:
        return LoadA();
    endtask
    task:
        return LoadB();
    endtask
endparallel;

A statement-form block runs concurrent work without collecting a result:

parallel:
    task:
        SaveA();
    endtask
    task:
        SaveB();
    endtask
endparallel

Host Functions called from ordinary task blocks must be registered as thread-safe. Task-local variables and function call stacks are isolated; RuntimeContext is shared and synchronized.

Host Trigger Dispatch

Host Trigger is v1.10.0's long-running runtime syntax.

@HostTrigger("LotArrived")
function OnLotArrived(lotId: string) -> void:
    Print("lot arrived: " + lotId);
    return;
endfunction

parallel:
    trigger task:
        dispatch;
    endtask
endparallel

@HostTrigger("Name") marks a user function as callable by the host through RuleScriptRuntime.TriggerAsync. A trigger task is only valid directly inside parallel. dispatch; waits for one queued host trigger request, invokes the matching trigger function, and then the trigger task continues waiting.

See Host Trigger for runtime lifecycle details.

JSON

var payload = JsonParse("{ \"robot\": { \"status\": \"OK\" }, \"items\": [1, 2, 3] }");

var status = payload.robot.status;
var second = payload.items[1];

if JsonExists(payload, "robot.status") then:
    result = JsonGet(payload, "robot.status");
endif

JSON objects become dictionaries, arrays become lists, and numbers become decimal values. JsonSet mutates existing dictionaries or lists in place.

Current Limitations

RuleScript does not include package management, generics, lambdas, delegates, language-level async / await, locks, channels, task handles, or fire-and-forget execution.

Clone this wiki locally