Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 5 Next »

This page uses BNF notation. Non-terminal names are bracketed by angle brackets. Meta symbols are ::= indicating the definition, square brackets indicating that what is within is optional, and the vertical bar indicating options or possible definitions of the non-terminal to the left of ::=. Uppercase non-terminal names indicate something that is not yet defined, or which is left undefined, or defined by hand-waving and/or verbiage. The proposed grammar is presented in pieces, hierarchically, with each piece as self-contained as possible, and further refined in subsequent sections.

The grammar used in the node pico engine can be perused at https://github.com/Picolab/pico-engine/blob/master/packages/krl-parser/src/grammar.ne, and is authoritative where it differs from the presentation here.

This page concentrates on the syntax of KRL, with numerous links to other pages which give examples and/or discuss run-time behavior.

Ruleset

In KRL, the ruleset is the unit of compilation, and also the smallest piece of functionality that can be installed in a pico.

<ruleset>      ::= ruleset <RID> { [<meta block>] [<global block>] [<rules>] }
<meta block>   ::= meta { [<meta entries>] }
<meta entries> ::= <META ENTRY> | <meta entries> <META ENTRY>
<global block> ::= global { [<bindings>] }
<bindings>     ::= <binding> | <bindings> ; <binding> [;]
<binding>      ::= <ID> = <EXPR>
<rules>        ::= <rule> | <rules> <rule>

Ruleset identifier (RID)

Rulesets are identified by RID, which must be unique per pico engine. A RID, like an identifier, can be made up of alphanumeric characters and the underscore character, but in addition can contain periods and dashes. We recommend using the Java convention of using the reversed name of a domain that you control, followed by a name that is unique within your organization. For example, we use the RID io.picolabs.wrangler for one of our internal rulesets. Anyone in the world following this convention will never choose a RID that exactly matches this one. Someone at IBM, for example, might want to define a "wrangler" ruleset, but they would name it com.ibm.wrangler. Thus the convention makes globally unique RID choice easier.

Meta block

This block is optional, but is generally present. The meta block is described informally in the Meta Section page.

Global block

This block is optional, but is generally present. The global block is a sequence of expressions which are evaluate as the ruleset is installed into a pico. The value of each expression is then bound to a name (the identifier on the left hand side of the equal sign). Names defined in the global block are in scope from their point of definition throughout the ruleset. There is no syntax (nor is there run-time support) for modification of the value bound to these names. This is similar to final in Java.

Besides use in the remainder of this ruleset, names can be shared with the outside world (by being named in the meta block shares entry). Names can also be provided to another ruleset which is using this ruleset as a module (by being named in the meta block provides entry).

Rules

Finally a ruleset may contain a sequence of rule definitions.

<rule>         ::= rule <ID> {
                    select when <eventex> [within <time expr>]
                    [foreach <EXPR> setting(<ID>[,<ID>])]
                    [pre { [<bindings>] }]
                    [[if <BOOL EXPR> then ]<ACTION>]
                    [<POSTLUDE>]
                  }
<time expr>   ::= <POS INT> <period>
<period>      ::= seconds | minutes | hours | days |weeks

A rule is identified by a simple identifier, which must be unique within the ruleset, and whose only use is to refer to the rule within the pico engine log.

Each rule may react to incoming events. Which rules actually do is determined by the rule selector, which consists of an event expression (either simple or complex), subject to an optional time limit for all of the needed events to come in. The syntax of event expressions is described later on.

Notice that a rule follows a definite sequence of evaluation. Assuming a rule is selected for evaluation, the evaluation will occur in order.

Looping

If a foreach is present, it will apply to the remainder of the rule, which will be evaluated once per item in the map or array computed by the <EXPR>. Each time through the loop, the first identifier in the setting clause will have a value from the map or array, and the second identifier (if named) will have the corresponding key or index value.

Prelude

If a prelude is present, it binds names to computed values. These names are in scope for the remainder of the rule.

Conditional action

The action is the heart of a rule. An action has effects on things outside of the pico: other picos on this engine, other picos on other engines, other systems, and whatever system sent the original event.

An action may be conditional on the result of a Boolean expression. For the (fairly common) case where we want a condition but have no action in mind, there is a special noop() action.

When the rule has a condition, and when the Boolean expression evaluates to true (or a truthy value), the rule is said to have fired. If there is no condition mentioned, the rule will also be said to have fired.

Postlude

The postlude is where effects to this same pico are specified.

Event expression

An event expression is a declarative way of expressing when the develper wishes the rule to be selected for evaluation.

<eventex>     ::= <ID 1> <ID 2> [ <matches> [ setting( <id list> ) ] ] [where <BOOL EXPR>]
                | ( <eventex> )
                | <eventex> <eventop> <eventex>
                | <eventop> ( <eventexes> )
                | <eventex> [not] between ( <eventexes> )
                | any <POS INT> ( <eventexes> )
                | <groupop> <POS INT> ( <eventex> ) [ <aggregateop>(<ID>) ]
<matches>     ::= <match> | <matches> <match>
<match>       ::= <ID> <REGEXP>
<id list>     ::= <ID> | <id list> , <ID>
<eventop>     ::= or | and | before | then | after
<eventexes>   ::= <eventex> | <eventexes> , <eventex>
<groupop>     ::= count | repeat
<aggregateop> ::= max | min | sum | avg | push

The simplest form is simply two identifers, the event domain and the event type. Event attributes can be matched against regular expressions. Portions of each attribute thus matched can be captured and named using setting. The number of identifiers given should match the total number of captures in all of the regular expressions for the simple event expression. If fewer are given, extra capture groups will not be retained. If more are given, the extra names will be bound to the null value.

A simple event expression can also use an escape into imperative programming, through the use of the optional where clause which will evaluate a Boolean expression.


  • No labels