Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: binding allowed in postlude

This page uses BNF notation. Non-terminal names are bracketed by enclosed in 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/blobtree/master/packages/krl-parser/src/grammar.ne, and is authoritative where it differs from the presentation here.

...

Rulesets are identified by RID, which and must be unique per within each 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 reversing 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.

...

This block is optional, but is generally present. The global block is a sequence of expressions which are evaluate evaluated 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.

...

Finally a ruleset may contain a sequence of rule definitions. Each rule definition follows this grammar:

Code Block
linenumberstrue
<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 files.

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.

...

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

...

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.

...

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

...

The simplest form is simply two identifers, the event domain <ID 1> and the event type <ID 2>. Event attributes can be matched against regular expressions. All of the matches must succeed for the rule to be selected for evaluation. Portions of each attribute thus matched can be captured and named using the setting clause. 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.

...

Code Block
<action>          ::= <simple action> | <compound action>
<compound action> ::= every { <action list> }
| choose <STRING EXPR> { <choice list> } <actions list>    ::= <action> | <action list> ;   | choose <ID> { <choice list> }
                    | choose ( <STRING EXPR> ) { <choice list> }
                    | sample { <choice list> }
<actions list>    ::= <action> | <action list> ; <action> [;]
<choice list>     ::= <choice> | <choice list> ; <choice> [;]
<choice>          ::= <ID> => <action>
<simple action>   ::= noop()
                    | <SEND DIRECTIVE>
                    | <HTTP POST>
                    | <DEFINED ACTION>
                    | <BUILT-IN ACTION>

...

The expression in the choose compound action must evaluate to a string which follows the rules for a KRL identifier. The id in a choice is given as a bare word, and the choices are considered in the order in which they appear in the choice list. The first choice for which the id equals the string computed by the expression has its action taken and the choose expression is complete. No further choices will be consideredand the choose compound action is complete. No further choices will be considered.

sample compound action

One of the actions will be chosen at random. See also the Compound Actions page.

noop() action

The grammar for the conditional action portion of a rule (repeated here for convenience> 

...

While the action has effects on things outside of the pico, the postlude can change the state of the pico or add select additional rules to for the event evaluation currently in progress (see the Event Loop Introduction page for more information).

...

Code Block
linenumberstrue
<postlude item>          ::= <postlude operation> [ <guard> ]
<guard>                  ::= if <BOOL EXPR>
                           | on final
<postlude operation>     ::= <postlude assignment>
                           | <postlude raise event>
                           | <binding>
<postlude assignment>    ::= ent:<ID> := <EXPR>
                           | clear ent:<ID>
<postlude raise event>   ::= raise <postlude event spec> [ for <STRING EXPR> ] [ attributes <MAP EXPR> ]
                           | last
<postlude event spec>    ::= <ID> event <STRING EXPR>
                           | event <STRING EXPR>

...

A pico is provided with entity variables by its installed rulesets. Entity variables can be assigned values only inside of rule postludes. An entity variable can be assigned a value (computed by an expression), or it can be cleared (line 87).

When an entity variable is mentioned in an expression (which can happen anywhere an expression can appear in a ruleset), and it does not exist in the pico/ruleset then the value is null.

...

In the first version of the syntax (line 810), the domain is given as a bare word between the keywords raise and event, and the type is usually a String constant (but can be computed by an expression computing a String which is a valid identifier.)

In the second (and newer) version of the syntax (line 911), the event is identified by a String expression which consists of a valid identifier for the domain followed by a colon followed by a valid identifier for the type.

...