Natural Language Syntax

◷ Reading Time: 12 minutes

Natural Language (NL) is a language used to model business rules that are close to your spoken language. The intention is to remove all of the noise of an XML model and emphasize the actual business rules using a business glossary, terms, and logic that are reusable across other types of logic.

As a result, rules are simpler to understand with less noise related to structure and/or types of the rule logic.

@name Test a person's identity

input person    
output valid

when Person has identity
    Person has name or
    Person has family
    ) and
    Email of person match "\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"
    /* Birth city must be available */
     Name of City of BirthPlace of person is not null and
     Name of City of BirthPlace of person is not empty
    ) or
    Age of person lt 18
   set valid to true

when Person has name
        Name of person is not null and
        Name of person is not empty

when Person has family
        Family of person is not null and
        Family of person is not empty

Rule Entry

  • Use to create a new business rule.
  • Use [CTRL]+[SPACE BAR] to bring up the suggestion box
    • To navigate between rules argument, press [TAB]
    • Select Parameter from the suggestion box and hit [ENTER]
    • Press [.] after parameter name and suggestion box navigates through the elements



The body of the rule contains:

  1. the name of the rule
  2. context
  3. set of logic
@name "name of rule document"
/* enable attribute is not mandatory, if it’s not set the default value will be added automatically. Default value is true. */
@enable {true | false} 


{logic 1}
{logic 2}
{logic n}


The logic is a when-then-otherwise-end block. then and otherwise are optional.

/* There might be one or more when the condition is available in the rule document */
when {name of logic}
    {Body of condition}
    {body of actions}  
    {body of actions}  

Please note that logic can have no name. In that case, remove the {name of logic} from after when.

When the {body of condition} is left empty, the actions on then will be executed automatically. If the {body of condition} is provided, they will be executed when {body of condition} is met otherwise the otherwise will be executed.

Parameterized Logic

In defining logic with parameters, { and } are used to enclose the parameter name

/*A logic with parameter named amount*/
when Add bonus of {amount} to total amount

/*A logic with NO parameters*/
when Print total

In calling a logic, just use its name. If the logic is parameterized then ( and ) are used to pass values

    Add bonus of (12.3) to total amount   and
    Print total

( and ) are mandatory to call the parameterized logic.


Adding {context} to rules has the following format:

/* List of input parameters */
 given | input variable1, variable2, …
 /* List of output parameteres */
 output variable1, variable2, …
 input output variable1, variable2, …

Body of condition

{Body of condition} has the following format:

{compare expression-1} {or|and|nor|xor|xnor}
{compare expression-2} {or|and|nor|xor|xnor}
{compare expression-n} 
/* Or may contains groups or nested groups. Group starts with ( and ends with ) */
    {Body of condition-1} {or|and|nor|xor|xnor}
    {Body of condition-2} {or|and|nor|xor|xnor}
    {Body of condition-n} 
) {or|and|nor|xor|xnor}
{Body of condition}


With using ( and ), Boolean logic can be grouped into sub-groups with higher priority. Also, groups/sub-groups can have their own negate attributes.

@negate {true | false} 

{logic 1} {or|and|nor|xor|xnor}
{logic 2} {or|and|nor|xor|xnor}
{logic n}

Compare expression

{compare expression} has the following format:

case 1: {left hand expression} {operator} {right hand expression}
case 2: name of logic
case 3: Any expression
case 1

{Right hand expression} can be any expression or {Value}.

{operator} can be

  1. Comparison operators
  2. Or any of: is, is not, match, not match

{left-hand expression} can be a {term} or can be any expression or {Value}.

case 2

When multiple logic is defined in a document, then it can have a name and call each other by name. In these cases, the parameter can be called by parentheses.

When multiple actions are expected as part of the consequence, then they should be separated or connected by either of the following:

  • and
  •  ; (semicolon)
  • set


Value can be primitive, constant values, or complex expressions (e.g., value [3; 45] is a range expression value).

{value} can be any Expression
Of Operator
{left or right hand expression} may have:
/* Flat property access */
{Property name} of {variable}
/* Or nested property access */
{Property name} of {Property name} of {Property name} of … {variable}


Logic with names:

Logic with no name:

Where r1, r2, r3, r4, and r5 are some other logic that is used in this logic.


Iterating over the list is available only on the then section of logic. If you need to iterate on a list (i.e., an array or collection of objects) you can use for.

for variableName in listName
  /* do your tasks */

When there is a condition to break the iteration, you include until to the for.

for variableName in listName until (expression)
  /* do your tasks */

The loop executes while the evaluated expression is false.

variableName must be defined as the parameter of the logic


Comments can be added to the rule document using /* and */.



Parameters can be defined in a standard way using the Declaration section or inside the Dsl section.

Or alternatively, they can be defined as part of the NL with the following keywords:

  1. input: defines input parameters.
  2. give: defines input parameters.
  3. output: defines output parameters.


[input|give|output] list of parameters, separated by comma


Local Parameters

Local [Parameter]s can be added at two different levels:

  1. Root scope
  2. Logic scope

In the example shown below ‘g’ is defined as a local parameter in the logic scope.

when split {names} into groups
    /* defining a local parameter in a Logic scope. */
    local g;
    g = split(names,',');

    /* rest of your logic */


In the body of logic, all of the operators that are described in the Expression section are accepted. On top of that, there are some specific operators in NL, as follows:

  1. is: To check equality
  2. is not: To check inequality
  3. match: To check the Regex pattern is matched
  4. match not: To check Regex pattern is not matched
  5. of: access to field and property on a parameter
  6. set/to: set a value to a parameter or its underlying structure. An alias to Val.



[value|parameter|Term] [match | not match] pattern


Email of person match "\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"

where Email is a property on person parameter.


Boolean expressions can be chained in the body of logic.


exp = [boolean value | term [is|is not] value | boolean expression] 
condition = exp [and|or|nor|xor] | exp... 


Sample 1

A rule like this:

R4: If all of the following are true, then the car’s potential theft rating is *low*.
 * car model is *not* on HTPA list
 * car’s price is between $20,000 and $45,000,

can be modelled as shown below:

Sample 2

In this example, we need to produce the result shown below (right) from a source (left):

We have two questions to answer:

  1. Cars in both groups (commonCars)
  2. Unique cars in each group (allUniqueCars)
input cars
commonCars: cars in both groups
allUniqueCars: unique cars in each groups
output commonCars, allUniqueCars 

local g1,g2,ab,ba,groups  

when main 
 split into groups; 
 /* Intersect of two groups */
 commonCars = g1 
      |select(x, x.Make, x.Model) 
      |intersect (
 g2 |select(x, x.Make, x.Model)
 /* difference of first group from second one */
 ab = g1
      |select (x, x.Make, x.Model) 
      |except (
 g2 |select (x, x.Make, x.Model)
 /* difference of second group from first one*/
 ba = g2
      |select (x, x.Make, x.Model) 
      |except (
  g1 |select (x, x.Make, x.Model)

 /* union the differences */
 allUniqueCars = ab |union (ba);
when split into groups
        /* As you see here, it allows you to split the logic
        and then you call it later by its name */ 
 groups = cars |groupBy (x, x.Group);
 g1 = groups[0];
 g2 = groups[1];

Sample 3: Auto premium

Calculation of the auto premium of a car in Natural Language: Add a bonus of (12.3) to the total amount

input car

when main
@processAll false

 test for Compact or
 test for Sedan or
 test for Luxury

when test for Compact
 (car.Style != 'Compact') or ((car.Model == 'abcd') and (car.ModelYear == 1999)) or
 car.ModelYear == 2002
 increase premium by (250) amount

when test for Sedan
 increase premium by (400) amount

when test for Luxury
 increase premium by (500) amount

when increase premium by {n} amount
 car.AutoPremium += n;


In an NL document, $context can be used to write notifications.

Format: $context.WriteInfo(groupName, message)
        $context.WriteWarning(groupName, message)
        $context.WriteError(groupName, message)
  • groupName: to categorize a set of notices in notification collection. null when it is not needed.
  • message: any text, expression, or value for the notice
Example: $context.WriteError(null, '$Assets is imputed.');

The other option is to use notification functions


The Inference capability allows rules dependencies to each other within a ruleset to be resolved at runtime, which means that the order of rules definition becomes irrelevant to the order of rules execution. To use the inference command, run on can be used:

run goal on {r1, r2, r3...}
  • goal (optional): Name of the parameter that is the goal to be answered
  • r1,r2…: name of the rules (i.e., when names)

When a goal is specified, only the rules related to that goal will be included in the execution rule set. Extra rules will be filtered out. If all the rules in the set must be executed, you can omit the goal.


when main
    run on {test for Compact, test for Sedan, test for Luxury}
Updated on April 8, 2022

Was this article helpful?

Related Articles