rumble.md 6.6 KB

Rumble

Rumble is Brawler's own event-driven language. Designed specifically to define rules (called sinks) and inject events to trigger the defined sinks. Rumble is an interpreted language with a dynamic type system.

Notation

Source code is Unicode text encoded in UTF-8. Single language statements are separated by a semicolon or a newline.

Constant values are usually enclosed in double quotes "" or single quotes '', both supporting escape sequences. Constant values can also be provided as raw strings prefixing a single or double quote with an 'r'. A raw string can contain any character including newlines and does not contain escape sequences.

Blocks are denoted with curley brackets. Most language constructs (conditions, loops, etc.) are very similar to other languages. All function calls start with an '@' sign. Comments start with a '#' sign and comment out the rest of the line.

Identifiers

Identifiers name program entities such as variables and sink names. An identifier is a sequence of one or more letters and digits.

Keywords

The following Keywords are reserved and cannot be used as Identifiers:

Sink Definition
	
	sink
	kindmatch
	scopematch
	statematch
	priority
	suppresses

Boolean operators

	and
	or
	not

Condition operators

	like        : String matches regex
	in          : List contains value
	beginswith  : String beginns with 
	endswith    : String ends with
	notin       : List does not contain

Constant terminals

	false
	true
	null

Conditional statements

	if
	elif
	else

Loop statements

	for
	break
	continue

Operators and punctuation

The following symbols are operators and punctuation:

Condition operators

	>=    : Greater or equals
	<=    : Greater or equals
	!=    : Not equal
	==    : Equal
	>     : Greater than
	<     : Less than

Grouping symbols

	(
	)
	[
	]
	{
	}

Sequence symbols

	,
	:
	;

Arithmetic operators

	+     : Arithmetic plus
	-     : Arithmetic minus
	*     : Arithmetic times
	/     : Arithmetic divide
	//    : Arithmetic integer divide
	%     : Arithmetic modulus

Assignment statement

	:=

Function call statement

	@

Data structure access

	$

Variable Assignments

A variable is a storage location for holding a value. Variables can hold single values (strings and numbers) or structures like an array or a map.

A variable is assinged with the assign operator ':='

a := 1
b := "test"
c := [1,2,3]
d := {1:2,3:4}

Multi-assignments are possible using lists:

[a, b] := [1, 2]

Expressions

Variables and constants can be combined with operators to form expressions.

1+2*5
5 >= a or 6 < b

Variable contents are interpreted depending on the situation so the following will evaluate to true:

a := "2"
3 == 1 + a

Boolean expressions can also be formed with variables:

a := 1 == 1
b := false or a

Accessing structures

Structures can be access via a '.' and a constant or a '$' and an expression.

An array value is accessed by a number indice starting with index 0. A map value is accessed by its key.

The following examples return always the number 2:

c := [1,2,3]
c.1

d := {1:2,3:4}
d.1

x := {1:[1,2,3],3:4}
x.1.1

Built-in functions

Several build in functions are available by default:

@log(level, message) Write a log message.

Example:

a:=1
@log("Info", "Value of a is: ", a)

@len(list) Return the size of a list.

Example:

@len([1,2,3])

@range(start, end, step) Iterator function for loops.

Example:

for a in @range(2, 10, 1) {
	@log("Info", "->", a)
}

@rootevent(name, kind, state, finish_event) Start a new event cascade. Can optionally have a 4th parameter which specifies a finish event which is injected after the event cascade has finished. The event has the state of the root event.

Example:

@rootevent("Start Event", "core.start", {
	"arg1" : "some value"
})

@event(name, kind, state, priority) Inject an event into an existing event cascade. This function can only be called if an active monitor is available (i.e. in the code block of a sink definition). The 4th parameter is optional.

Example:

@event("Another Event", "core.next", {
	"arg1" : "some value"
})

Loop statements

All loops in Rumble are done with the 'for' block statement. Counting loops are done with the 'range' function. The following code iterates from 2 until 10 in steps of 2:

for a in @range(2, 10, 2) {
	@log("Info", "->", a)
}

Conditional loops are done using conditions after the for statement:

a := 10
for a > 0 {
	@log("Info", "->", a)
	a := a - 1
}

It is possible to loop over lists and even have multiple assignments:

for [a,b] in [[1,1], [2,2], [3,3]] {
	@log("Info", " ", a, " == ", b)
}

or

x := { "c":0, "a":2, "b":4}
for [a, b] in x {
	@log("Info", "->", a, "-", b)
}

Conditional statements

The "if" statement specifies the conditional execution of multiple branches:

if a == 1 {
    a := a + 1	
} elif a == 2 {
	a := a + 2
} else {
    a := 99
}

Sinks

Event sinks trigger on events. An event is either injected via 'event' and 'rootevent' or via external sources (e.g. a datastore).

The code inside the sink has access to some default objects:

	event     : The event which triggered the sink
	monitor   : The current monitor of the event
	processor : The current processor which executes the code

Events have the following structure:

{
    name  : A name which identifies the event
    kind  : The event kind
    state : A map containing additional information
}

A sink definition must contain the following information:

  • [name] A name which identifies the sink.
  • [kindmatch] Match on event kinds: A list of strings in dot notation which describes event kinds. May contain '*' characters as wildcards.
  • [scopematch] Match on event cascade scope: A list of strings in dot notation which describe the required scopes which are required for this rule to trigger. The included / excluded scopes for an event are stored in its monitor.
  • [statematch] Match on event state: A simple list of required key / value states in the event state. Nil values can be used as wildcards (i.e. match is only on key).
  • [priority] Sinks are sorted by their priority (0 being the highest) before their code is executed.
  • [suppresses] A list of sinks (identified by their name) which should be suppressed if this sink executes.

Example:

sink "rule1" 
    r'
    Some description.
    '
    kindmatch [ "core.*" ],
	scopematch [ "analysis.simple", "analysis.deep" ],
	statematch { "val" : NULL },
	priority 10,
	suppresses [ "rule2" ]
{
    # Some code
}