Skip to content

Latest commit

 

History

History
9369 lines (7135 loc) · 178 KB

10-expression-language-FEEL.adoc

File metadata and controls

9369 lines (7135 loc) · 178 KB

Expression Language (FEEL)

Introduction

In DMN, all decision logic is represented as boxed expressions. Clause 7.2 introduced the concept of the boxed expression and defined two simple kinds: boxed literal expressions and boxed invocations. Clause 8 defined decision tables, a very important kind of boxed expression. This section completes the graphical notation for decision logic, by defining other kinds of boxed expressions.

The expressions 'in the boxes' are FEEL expressions. FEEL stands for Friendly Enough Expression Language and it has the following features:

Side-effect freeSimple data model with numbers, dates, strings, lists, and contextsSimple syntax designed for a wide audienceThree-valued logic (true, false, null)This section also completely specifies the syntax and semantics of FEEL. The syntax is specified as a grammar (10.3.1). The subset of the syntax intended to be rendered graphically as a boxed expression is also specified as a meta-model (10.5).

FEEL has two roles in DMN:

As a textual notation in the boxes of boxed expressions such as decision tables.As a slightly larger language to represent the logic of expressions and DRGs for the main purpose of composing the semantics in a simple and uniform way. Notation

Boxed Expressions

This section builds on the generic notation for decision logic and boxed expressions defined in clause 7.2.

We define a graphical notation for decision logic called boxed expressions. This notation serves to decompose the decision logic model into small pieces that can be associated with DRG artifacts. The DRG plus the boxed expressions form a complete, mostly graphical language that completely specifies Decision Models.

A boxed expression is either:

a decision tablea boxed FEEL expressiona boxed invocationa boxed contexta boxed lista relationa boxed functiona boxed conditionala boxed filter, ora boxed iteratorBoxed expressions are defined recursively, i.e., boxed expressions can contain other boxed expressions. The top-level boxed expression corresponds to the decision logic of a single DRG artifact. This boxed expression SHALL have a name box that contains the name of the DRG artifact. The name box may be attached in a single box on top, as shown in Figure 10‑1:

image

[_Toc87278840 .anchor]#Figure 10‑1: Boxed expression

Alternatively, the name box and expression box can be separated by white space and connected on the left side with a line, as shown in Figure 10‑2:

image

[_Toc87278841 .anchor]#Figure 10‑2: Boxed expression with separated name and expression boxes

Graphical tools are expected to support appropriate graphical links, for example, clicking on a decision shape opens a decision table.

Color is suggested, but does not influence the meaning. In section 10:

Green is used for names of parameters, names of context entries, keywords in boxed conditionals and boxed iterators, and brackets in boxed filters.Embedded decision tables are colored as in section 8.

Decision Tables

The executable decision tables defined here use the same notation as the decision tables defined in Clause 8. Their execution semantics is defined in clause 10.3.2.10.

Boxed FEEL expression

A boxed FEEL expression is any FEEL expression e, as defined by the FEEL grammar (clause 10.3.1), in a table cell, as shown in Figure 10‑3:

image

[_Toc87278842 .anchor]#Figure 10‑3: Boxed FEEL expression

The meaning of a boxed expression containing e is FEEL(*e, *s), where s is the scope. The scope includes the context derived from the containing DRD as described in 10.4, and any boxed contexts containing e.

It is usually good practice to make e relatively simple, and compose small boxed expressions into larger boxed expressions.

Boxed Invocation

The syntax for boxed invocation is described in clause 7.2.3. This syntax may be used to invoke any function (e.g., business knowledge model, FEEL built-in function, boxed function definition).

The box labeled 'invoked business knowledge model' can be any boxed expression whose value is a function, as shown in Figure 10‑4 :

Table 1. [_Toc87278974 .anchor]#Table 44: Examples of equivalence and conformance relations

Name

function-valued expression

parameter 1

binding expression 1

parameter 2

binding expression 2

parameter n

binding expression n

[_Toc87278843 .anchor]#Figure 10‑4: Boxed invocation

The boxed syntax maps to the textual syntax defined by grammar rules 38, 39, 40, 41. Boxed invocation uses named parameters. Positional invocation can be achieved using a boxed expression containing a textual positional invocation.

The boxed syntax requires at least one parameter. A parameterless function must be invoked using the textual syntax, e.g., as shown in Figure 10‑5.

[_Toc87278844 .anchor]#Figure 10‑5: Parameterless function

Formally, the meaning of a boxed invocation is given by the semantics of the equivalent textual invocation, e.g., function-valued expression(parameter1: binding expression1, parameter2: binding expression2, …​).

Boxed Context

A boxed context is a collection of n (name, value) pairs with an optional result value. The names SHALL be distinct within a context. Each pair is called a context entry. Context entries may be separated by whitespace and connected with a line on the left (top). The intent is that all the entries of a context should be easily identified by looking down the left edge of a vertical context or across the top edge of a horizontal context. Cells SHALL be arranged in one of the following ways (see Figure 10‑6, Figure 10‑7):

Table 2. [_Toc87278975 .anchor]#Table 45: Examples of singleton list conversions

Name 1

Value 1

Name 2

Value 2

Name n

Value n

Result

[_Toc87278845 .anchor]#Figure 10‑6: Vertical context

Table 3. [_Toc87278976 .anchor]#Table 46: Semantics of decision table

Name 1

Name 2

Name n

Result

Value 1

Value 2

Value n

[_Toc87278846 .anchor]#Figure 10‑7: Horizontal context

The context entries in a context are often used to decompose a complex expression into simpler expressions, each with a name. These context entries may be thought of as intermediate results. For example, contexts without a final Result box are useful for representing case data (see Figure 10‑8).

Table 4. [_Toc87278977 .anchor]#Table 47: Mapping between FEEL and other domains

Applicant Data

Age

51

MaritalStatus

"M"

EmploymentStatus

"EMPLOYED"

ExistingCustomer

false

Monthly

Income

10000.00

Repayments

2500.00

Expenses

3000.00

[_Toc87278847 .anchor]#Figure 10‑8: Use of context entries

Contexts with a final result box are useful for representing calculations (see Figure 10‑9).

Table 5. [_Toc87278978 .anchor]#Table 48: Semantics of FEEL functions

Eligibility

Age

Applicant. Age

Monthly Income

Applicant. Monthly. Income

Pre-Bureau Risk Category

Affordability. Pre-Bureau Risk Category

Installment Affordable

Affordability. Installment Affordable

if Pre-Bureau Risk Category = "DECLINE" or Installment Affordable = false or

Age < 18 or

Monthly Income < 100 then "INELIGIBLE"

else "ELIGIBLE"

[_Toc87278848 .anchor]#Figure 10‑9: Use of final result box

When decision tables are (non-result) context entries, the output cell can be used to name the entry, thus saving space. Any format decision table can be used in a vertical context. A jagged right edge is allowed. Whitespace between context entries may be helpful. See Figure 10‑10.

Table 6. [_Toc87278979 .anchor]#Table 49: Semantics of other FEEL expressions

Name 1

Value 1

Name 2

Name n

Value n

Result

[_Toc87278849 .anchor]#Figure 10‑10: Vertical context with decision table entry

The names SHALL be legal FEEL names. The values and optional result are boxed expressions.

Boxed contexts may have a decision table as the result, and use the named context entries to compute the inputs, and give them names. For example (see Figure 10‑11):

Table 7. [_Toc87278980 .anchor]#Table 50: Semantics of conjunction and disjunction

Post-Bureau Risk Category

Existing Customer

Applicant. ExistingCustomer

Credit Score

Report. CreditScore

Application Risk Score

Affordability Model(Applicant, Product). Application Risk Score

U

Existing Customer

Application Risk Score

Credit Score

Post-Bureau Risk Category

1

true

⇐120

<590

“HIGH”

2

[590..610]

“MEDIUM”

3

>610

“LOW”

4

>120

<600

“HIGH”

5

[600..625]

“MEDIUM”

6

>625

“LOW”

7

false

⇐100

<580

“HIGH”

8

[580..600]

“MEDIUM”

9

>600

“LOW”

10

>100

<590

“HIGH”

11

[590..615]

“MEDIUM”

12

>615

“LOW”

[_Toc87278850 .anchor]#Figure 10‑11: Use of boxed expressions with a decision table

Formally, the meaning of a boxed context is \{ “Name 1”: Value 1, “Name 2”: Value 2, …​, “Name n”: Value n } if no Result is specified. Otherwise, the meaning is \{ “Name 1”: Value 1, “Name 2”: Value 2, …​, “Name n”: Value n, “result”: Result }.result. Recall that the bold face indicates elements in the FEEL Semantic Domain. The scope includes the context derived from the containing DRG as described in 10.4.

Boxed context entries for contexts that do not have a result box are accessible outside the context (as QNs), subject to the scope rules defined in clause 10.3.2.11. Boxed context entries for contexts that have a result box are not accessible outside the context.

Boxed List

A boxed list is a list of n items. Cells SHALL be arranged in one of the following ways (see Figure 10‑12, Figure 10‑13):

image

[_Toc87278851 .anchor]#Figure 10‑12: Vertical list

[_Toc87278852 .anchor]#Figure 10‑13: Horizontal list

Line styles are normative. The items are boxed expressions. Formally, the meaning of a boxed list is just the meaning of the list, i.e., [ Item 1, Item 2, …​, Item n ]. The scope includes the context derived from the containing DRG as described in 10.4.

Relation

A vertical list of homogeneous horizontal contexts (with no result cells) can be displayed with the names appearing just once at the top of the list, like a relational table, as shown in Figure 10‑14:

Table 8. [_Toc87278981 .anchor]#Table 51: Semantics of negation

Name 1

Name 2

Name n

Value 1a

Value 2a

Value na

Value 1b

Value 2b

Value nb

Value 1m

Value 2m

Value nm

  • + [_Toc87278853 .anchor]#*Figure 10‑14: Relation

Boxed Function

A Boxed Function Definition is the notation for parameterized boxed expressions.

The boxed expression associated with a Business Knowledge Model SHALL be a boxed function definition or a decision table whose input expressions are assumed to be the parameter names.

A boxed function has 3 cells:

1. Kind, containing the initial letter of one of the following:

FEELPMMLJava The Kind box can be omitted for FEEL functions, including decision tables.

Parameters: 0 or more comma-separated names, in parenthesesBody: a boxed expression

The 3 cells SHALL be arranged as shown in Figure 10‑15:

Table 9. [_Toc87278982 .anchor]#Table 52: General semantics of equality and inequality

K

(Parameter1, Parameter2, …)

Body

[_Toc87278854 .anchor]#Figure 10‑15: Boxed function definition

For FEEL functions, denoted by Kind FEEL or by omission of Kind, the Body SHALL be a FEEL expression that references the parameters. For externally defined functions denoted by Kind Java, the Body SHALL be a context as described in 10.3.2.13.3 and the form of the mapping information SHALL be the java form. For externally defined functions denoted by Kind PMML, the Body SHALL be a context as described in 10.3.2.13.3 and the form of the mapping information SHALL be the pmml form.

Formally, the meaning of a boxed function is just the meaning of the function, i.e., FEEL(funcion(Parameter1, Parameter2, …​) Body) if the Kind is FEEL, and FEEL(funcion(Parameter1, Parameter2, …​) external Body) otherwise. The scope includes the context derived from the containing DRG as described in 10.4.

Boxed conditional

Boxed conditional offers a visual representation of an if statement using three rows. The first one is labelled “if”; the second one is labelled “then” and the last one is labelled “else”. In the right part, another FEEL expression is expected. The expression in the “if” part MUST resolve to a boolean.

Table Description automatically generated

[_Toc87278855 .anchor]#Figure 10‑16: Boxed conditional

Table Description automatically generated

[_Toc87278856 .anchor]#Figure 10‑17: Use of conditional expression with decision table and invocation

Boxed filter

Boxed filter offers a visual representation of collection filtering. The top part is an expression that is the collection to be filtered. The bottom part, between the square brackets, holds the filter expression. The expression in the top part MUST resolve to a collection. The expression in the bottom part MUST resolve to a Boolean.

Table Description automatically generated

[_Toc87278857 .anchor]#Figure 10‑18: Filter expression

Color is suggested but it is considered a good practice to have a different color for the square brackets, so the filtering expression is easier to see.

Table Description automatically generated

[_Toc87278858 .anchor]#Figure 10‑19: Use of filter expression with a list expression

Boxed iterator

Boxed iterator offers a visual representation of an iterator statement. There are three flavors to it: for loop and quantified expression some and every.

For the for loop, the three rows are labelled “for”, “in” and “return”. The right part of the “for” displays the iterator variable name. The second row holds an expression representing the collection that will be iterated over. The expression in the in row MUST resolve to a collection. The last row contains the expression that will process each element of the collection.

image

[_Toc87278859 .anchor]#Figure 10‑20: For expression

Table Description automatically generated

[_Toc87278860 .anchor]#Figure 10‑21: Use of for expression that returns a context

Every and some expression have a similar structure. The only difference between the two is the caption on the first line which is “every” or “some”. The second line is labelled “in” and the last one “satisfies”. The right part of the first line is the iterator variable name. The expression defined in the second row is the collection that will be tested. The expression in the in row MUST resolve to a collection. The last line is an expression that will be evaluated on each item. The expression defined in the satisfies MUST resolve to a boolean.

Table Description automatically generated

[_Toc87278861 .anchor]#Figure 10‑22: Every expression

Table Description automatically generated

[_Toc87278862 .anchor]#Figure 10‑23: Use of every with a list expression

Table Description automatically generated

[_Toc87278863 .anchor]#Figure 10‑24: Some expression

Table Description automatically generated with medium confidence

[_Toc87278864 .anchor]#Figure 10‑25: Use of some with a relation and a decision table

FEEL

A subset of FEEL, defined in the next section, serves as the notation "in the boxes" of boxed expressions. A FEEL object is a number, a string, a date, a time, a duration, a function, a context, or a list of FEEL objects (including nested lists).

Note: A JSON object is a number, a string, a context (JSON calls them maps) or a list of JSON objects. So, FEEL is an extension of JSON in this regard. In addition, FEEL provides friendlier syntax for literal values, and does not require context keys to be quoted.

Here we give a "feel" for the language by starting with some simple examples.

Comparison of ranges

Ranges and lists of ranges appear in decision table input entry, input value, and output value cells. In the examples in Table 39, this portion of the syntax is shown underlined. Strings, dates, times, and durations also may be compared, using typographical literals defined in section 7.2.2.1.

Table 10. [_Toc87278983 .anchor]#Table 53: Specific semantics of equality
FEEL Expression Value

5 in (⇐5 )

true

5 in ( (5..10] )

false

5 in ( 5..10] )

true

5 in (4, 5, 6)

true

5 in (<5, >5)

false

2012-12-31 in ( (2012-12-25..2013-02-14) )

true

Numbers

FEEL numbers and calculations are exemplified in Table 40.

Table 11. [_Toc87278984 .anchor]#Table 54: Specific semantics of inequality
FEEL Expression Value

decimal(1, 2)

1.00

0.45

3.0000

1 + 3/2*2 - 2**3

-4.0

1/3

0.3333333333333333333333333333333333

decimal(1/3, 2)

0.33

1 = 1.000

true

1.01/2

0.505

decimal(0.505, 2)

0.50

decimal(0.515, 2)

0.52

1.0*10**3

1000.0

Full FEEL Syntax and Semantics

Clause 9 introduced a subset of FEEL sufficient to support decision tables for Conformance Level 2 (see clause 2). The full DMN friendly-enough expression language (FEEL) required for Conformance Level 3 is specified here. FEEL is a simple language with inspiration drawn from Java, JavaScript, XPath, SQL, PMML, Lisp, and many others.

The syntax is defined using grammar rules that show how complex expressions are composed of simpler expressions. Likewise, the semantic rules show how the meaning of a complex expression is composed from the meaning of constituent simper expressions.

DMN completely defines the meaning of FEEL expressions that do not invoke externally-defined functions. There are no implementation-defined semantics. FEEL expressions (that do not invoke externally-defined functions) have no side- effects and have the same interpretation in every conformant implementation. Externally-defined functions SHOULD be deterministic and side-effect free.

Syntax

FEEL syntax is defined as grammar here and equivalently as a UML Class diagram in the meta-model (10.5)

Grammar notation

The grammar rules use the ISO EBNF notation. Each rule defines a non-terminal symbol S in terms of some other symbols S1, S2, …​ The following table summarizes the EBNF notation.

Table 12. [_Toc87278985 .anchor]#Table 55: Semantics of decision table syntax
_ Example _ _ Meaning _

S = S1 ;

Symbol S is defined in terms of symbol S1

_S1

S2_ __

Either S1 or S2

S1, S2

S1 followed by S2

[S1]

S1 occurring 0 or 1 time

{S1}

S1 repeated 0 or more times

k * S1

S1 repeated k times

"and"

We extend the ISO notation with character ranges for brevity, as follows:

A character range has the following EBNF syntax:

character range = "[", low character, "-", high character, "]" ;

low character = unicode character ;

high character = unicode character ;

unicode character = simple character | code point ;

code point = "\u", 4 * hexadecimal digit | "\U", 6 * hexadecimal digit;

hexadecimal digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |

"a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" | "E" | "f" | "F" ;

A simple character is a single Unicode character, e.g. a, 1, $, etc. Alternatively, a character may be specified by its hexadecimal code point value, prefixed with \u.

Every Unicode character has a numeric code point value. The low character in a range must have numeric value less than the numeric value of the high character.

For example, hexadecimal digit can be described more succinctly using character ranges as follows:

hexadecimal digit = [0-9] | [a-i | [A-F] ;

Note that the character range that includes all Unicode characters is [\u0-\u10FFFF].

Grammar rules

The complete FEEL grammar is specified below. Grammar rules are numbered, and in some cases alternatives are lettered, for later reference. Boxed expression syntax (rule 53) is used to give execution semantics to boxed expressions.

1. expression =

boxed expression |textual expression ;2. textual expression =

for expression | if expression | quantified expression |disjunction |conjunction |comparison |arithmetic expression |instance of |path expression | filter expression | function invocation |literal | simple positive unary test | name | "(" , expression , ")" ;3. textual expressions = textual expression , \{ "," , textual expression } ;

4. arithmetic expression =

addition | subtraction |multiplication | division |exponentiation |arithmetic negation ;5. simple expression = arithmetic expression | simple value ;

6. simple expressions = simple expression , \{ "," , simple expression } ;

7. simple positive unary test =

( "<" | "⇐" | ">" | ">=" ) , endpoint |interval ;8. interval = ( open interval start | closed interval start ) , endpoint , ".." , endpoint , ( open interval end | closed interval end ) ;

9. open interval start = "(" | "]" ;

10. closed interval start = "[" ;

11. open interval end = ")" | "[" ;

12. closed interval end = "]" ;

13. positive unary test = expression ;

14. positive unary tests = positive unary test , \{ "," , positive unary test } ;

15. unary tests =

positive unary tests |"not", " (", positive unary tests, ")" |"-"16. endpoint = expression ;

17. simple value = qualified name | simple literal ;

18. qualified name = name , \{ "." , name } ;

19. addition = expression , "+" , expression ;

20. subtraction = expression , "-" , expression ;

21. multiplication = expression , "*" , expression ;

22. division = expression , "/" , expression ;

23. exponentiation = expression, "**", expression ;

24. arithmetic negation = "-" , expression ;

25. name = name start , \{ name part | additional name symbols } ;

26. name start = name start char, \{ name part char } ;

27. name part = name part char , \{ name part char } ;

28. name start char = "?" | [A-Z] | "_" | [a-z] | [\uC0-\uD6] | [\uD8-\uF6] | [\uF8-\u2FF] | [\u370-\u37D] | [\u37F-\u1FFF] | [\u200C-\u200D] | [\u2070-\u21 8F] | [\u2C00-\u2FEF] | [\u3001 -\uD7FF] | [\uF900-\uFDCF] | [\uFDF0-\uFFFD] | [\u10000-\uEFFFF] ;

29. name part char = name start char | digit | \uB7 | [\u0300-\u036F] | [\u203F-\u2040] ;

30. additional name symbols = "." | "/" | "-" | "’" | "+" | "*" ;

31. literal = simple literal | "null" ;

32. simple literal = numeric literal | string literal | boolean literal | date time literal ;

33. string literal = """, \{ character – (""" | vertical space) | string escape sequence}, """ ;

34. boolean literal = "true" | "false" ;

35. numeric literal = [ "-" ] , ( digits , [ ".", digits ] | "." , digits ) ;

36. digit = [0-9] ;

37. digits = digit , {digit} ;

38. function invocation = expression , parameters ;

39. parameters = "(" , ( named parameters | positional parameters ) , ")" ;

40. named parameters = parameter name , ":" , expression , \{ "," , parameter name , ":" , expression } ;

41. parameter name = name ;

42. positional parameters = [ expression , \{ "," , expression } ] ;

43. path expression = expression , "." , name ;

44. for expression = "for" , name , "in" , iteration context \{ "," , name , "in" , iteration context } , "return" , expression ;

45. if expression = "if" , expression , "then" , expression , "else" expression ;

46. quantified expression = ("some" | "every") , name , "in" , expression , \{ "," , name , "in" , expression } , "satisfies" ,

expression ;

47. disjunction = expression , "or" , expression ;

48. conjunction = expression , "and" , expression ;

49. comparison =

expression , ( "=" | "!=" | "<" | "⇐" | ">" | ">=" ) , expression |expression , "between" , expression , "and" , expression |expression , "in" , positive unary test |expression , "in" , " (", positive unary tests, ")" ;50. filter expression = expression , "[" , expression , "]" ;

51. instance of = expression , "instance" , "of" , type ;

52. type =

qualified name |

"range" "<" type ">" |

"list" "<" type ">" |

"context" "<" name ":" type \{ "," name ":" type } ">" | "function" "<" [ type \{ ", " type } ] ">" "→" type

;

53. boxed expression = list | function definition | context ;

54. list = "[" , [ expression , \{ "," , expression } ] , "]" ;

55. function definition = "function" , "(" , [ formal parameter \{ "," , formal parameter } ] , ")" , [ "external" ] , expression ;

56. formal parameter = parameter name [":" type ] ;

57. context = "\{" , [context entry , \{ "," , context entry } ] , "}" ;

58. context entry = key , ":" , expression ;

59. key = name | string literal ;

60. date time literal = at literal | function invocation;

61. white space = vertical space | \u0009 | \u0020 | \u0085 | \u00A0 | \u1 680 | \u1 80E | [\u2000-\u200B] | \u2028 | \u2029 | \u202F | \u205F | \u3000 | \uFEFF ;

62. vertical space = [\u000A-\u000D]

63. iteration context = expression, [ “..”, expression ];

64. string escape sequence = "\'" | "\"" | "\\" | "\n" | "\r" | "\t" | code point;

65. at literal = “@”, string literal

Additional syntax rules:

Operator precedence is given by the order of the alternatives in grammar rules 1, 2 and 4, in order from lowest to highest. E.g., (boxed) invocation has higher precedence than multiplication, multiplication has higher precedence than addition, and addition has higher precedence than comparison. Addition and subtraction have equal precedence, and like all FEEL infix binary operators, are left associative.Java-style comments can be used, i.e. '//' to end of line and /* …​ */.In rule 62, the only permitted functions are the builtins date, time, date and time, and duration.The string in rule 65 must follow the date string, time string, date and time string or duration string syntax, as detailed in section 10.3.4.1. Literals, data types, built-in functions

FEEL supports literal syntax for numbers, strings, booleans, date, time, date and time, duration, and null. (See grammar rules, clause 10.3.1.2). Literals can be mapped directly to values in the FEEL semantic domain (clause 10.3.2.1).

FEEL supports the following datatypes:

NumberStringBooleandays and time durationyears and months durationdatetimedate and timelistrangecontextfunctionTokens, Names and White space

A FEEL expression consists of a sequence of tokens, possibly separated with white space (grammar rule 63). A token is a sequence of Unicode characters, either:

A literal terminal symbol in any grammar rule other than grammar rule 30. Literal terminal symbols are enclosed in double quotes in the grammar rules, e.g., “and”, “+”, “=”, orA sequence conforming to grammar rule 28, 29, 35, or 37For backward compatibility reasons, “list”, “context” and “range” from grammar rule 52 are not considered literal terminal symbols.

White space (except inside strings) acts as token separators. Most grammar rules act on tokens, and thus ignore white space (which is not a token).

A name (grammar rule 27) is defined as a sequence of tokens. I.e. the name IncomeTaxesAmount is defined as the list of tokens [ Income, Taxes, Amount ]. The name Income+Expenses is defined as the list of tokens [ Income, + , Expenses ]. A consequence of this is that a name like Phone Number with one space in between the tokens is the same as Phone Number with several spaces in between the tokens.

A name start (grammar rule 26) SHALL NOT be a literal terminal symbol.

A name part (grammar rule 27) MAY be a literal terminal symbol.

Contexts, Lists, Qualified Names, and Context Lists

A context is a map of key-value pairs called context entries, and is written using curly braces to delimit the context, commas to separate the entries, and a colon to separate key and value (grammar rule 57). The key can be a string or a name. The value is an expression.

A list is written using square brackets to delimit the list, and commas to separate the list items (grammar rule 54).

Contexts and lists can reference other contexts and lists, giving rise to a directed acyclic graph. Naming is path based. The qualified name (QN) of a context entry is of the form N1.N2 …​ Nn where N1 is the name of an in-scope context.

Nested lists encountered in the interpretation of N1.N2 …​ Nn are preserved. E.g.,

\{b: [1]}}, \{a: \{b: [2.1, 2.2]}}, \{a: \{b: [3]}}, \{a: \{b: [4, 5]}}].a.b =[1]}, \{b: [2.1,2.2]}, \{b: [3]}, \{b: [4, 5]}].b =[[1], [2.1, 2.2], [3], [4, 5]]

Nested lists can be flattened using the flatten() built-in function (10.3.4).

Ambiguity

FEEL expressions reference InformationItems by their qualified name (QN), in which name parts are separated by a period. For example, variables containing components are referenced as [varName].[componentName]. Imported elements such as InformationItems and ItemDefinitions are referenced by namespace-qualified name, in which the first name part is the name specified by the Import element importing the element. For example, an imported variable containing components is referenced as [import name].[varName].[componentName].

Because names are a sequence of tokens, and some of those tokens can be FEEL operators and keywords, context is required to resolve ambiguity. For example, the following could be names or other expressions:

a-ba – bwhat if?Profit and lossAmbiguity is resolved using the scope. Name tokens are matched from left to right against the names in-scope, and the longest match is preferred. In the case where the longest match is not desired, parenthesis or other punctuation (that is not allowed in a name) can be used to disambiguate a FEEL expression. For example, to subtract b from a if a-b is the name of an in-scope context entry, one could write (a)-(b). Notice that it does not help to write a - b, using space to separate the tokens, because the space is not part of the token sequence and thus not part of the name.

Semantics

FEEL semantics is specified by mapping syntax -fragments to values in the FEEL semantic domain. Literals (clause 10.3.1.3) can be mapped directly. Expressions composed of literals are mapped to values in the semantic domain using simple logical and arithmetic operations on the mapped literal values. In general, the semantics of any FEEL expression are composed from the semantics of its sub-expressions.

Semantic Domain

The FEEL semantic domain D consists of an infinite number of typed values. The types are organized into a lattice called L.

The types include:

simple datatypes such as number, boolean, string, date, time, and durationconstructed datatypes such as functions, lists, and contextsthe Null type, which includes only the null valuethe special type Any, which includes all values in DA function is a lambda expression with lexical closure or is externally defined by Java or PMML. A list is an ordered collection of domain elements, and a context is a partially ordered collection of (string, value) pairs called context entries.

We use italics to denote syntactic elements and boldface to denote semantic elements. For example, FEEL([1+ 1, 2+2]*) is [2, 4]*

Note that we use bold [] to denote a list in the FEEL semantic domain, and bold numbers 2, 4 to denote those decimal values in the FEEL semantic domain.

Equality, Identity and Equivalence

The semantics of equality are specified in the semantic mappings in clause 10.3.2.15. In general, the values to be compared must be of the same kind, for example, both numbers, to obtain a non-null result.

Identity simply compares whether two objects in the semantic domain are the same object. We denote the test for identity using infix is, and its negation using infix is not. For example, FEEL( "1" = 1) is null. Note that is never results in null.

Every FEEL expression e in scope s can be mapped to an element e in the FEEL semantic domain. This mapping defines the meaning of e in s. The mapping may be written e is FEEL(e,s). Two FEEL expressions e1 and e2 are equivalent in scope s if and only if FEEL(e1,s) is FEEL(e2,s). When s is understood from context (or not important), we may abbreviate the equivalence as e1 is e2.

Semantics of literals and datatypes

FEEL datatypes are described in the following sub-sections. The meaning of the datatypes includes:

A mapping from a literal form (which in some cases is a string) to a value in the semantic domain.A precise definition of the set of semantic domain values belonging to the datatype, and the operations on them. Each datatype describes a (possibly infinite) set of values. The sets for the datatypes defined below are disjoint. We use italics to indicate a literal and boldface to indicate a value in the semantic domain.

number

FEEL Numbers are based on IEEE 754-2008 Decimal128 format, with 34 decimal digits of precision and rounding toward the nearest neighbor with ties favoring the even neighbor. Numbers are a restriction of the XML Schema type precisionDecimal, and are equivalent to Java BigDecimal with MathContext DECIMAL 128.

Grammar rule 35 defines literal numbers. Literals consist of base 10 digits and an optional decimal point. –INF, +INF, and NaN literals are not supported. There is no distinction between -0 and 0. The number(from, grouping separator, decimal separator) built-in function supports a richer literal format. E.g., FEEL(number("1. 000.000,01 ", ". ", ",")) = 1000000.01.

FEEL does not support a literal scientific notation. E.g., 1 .2e3 is not valid FEEL syntax. Use 1.2*10**3 instead.

A FEEL number is represented in the semantic domain as a pair of integers (p,s) such that p is a signed 34 digit integer carrying the precision information, and s is the scale, in the range [−611 1..6176]. Each such pair represents the number p/10s. To indicate the numeric value, we write value(p,s). E.g. value(100,2) = 1. If precision is not of concern, we may write the value as simply 1. Note that many different pairs have the same value. For example, value(1,0) = value(10,1) = value(100,2).

There is no value for notANumber, positiveInfinity, or negativeInfinity. Use null instead.

string

Grammar rule 33 defines literal strings as a double-quoted sequence of Unicode characters (see [.underline#https://unicode.org/glossary/#character),] e.g., "abc". The supported Unicode character range is [\u0-\u10FFFF]. The string literals are described by rule 33. The corresponding Unicode code points are used to encode a string literal.

imageThe literal string "abc" is mapped to the semantic domain as a sequence of three Unicode characters a, b, and c, written "abc". The literal "\ U01F4 0E" is mapped to a sequence of one Unicode character written "ὀ" corresponding to the code point U+1F40E.

boolean

The Boolean literals are given by grammar rule 34. The values in the semantic domain are true and false.

time

Times in FEEL can be expressed using either a time literal (see grammar rule 65) or the time() built-in function (See 10.3.4.1). We use boldface time literals to represent values in the semantic domain.

A time in the semantic domain is a value of the XML Schema time datatype. It can be represented by a sequence of numbers for the hour, minute, second, and an optional time offset from Universal Coordinated Time (UTC). If a time offset is specified, including time offset = 00:00, the time value has a UTC form and is comparable to all time values that have UTC forms. If no time offset is specified, the time is interpreted as a local time of day at some location, whose relationship to UTC time is dependent on time zone rules for that location, and may vary from day to day. A local time of day value is only sometimes comparable to UTC time values, as described in XML Schema Part 2 Datatypes.

A time t can also be represented as the number of seconds since midnight. We write this as valuet(t). E.g., valuet(01:01:01) = 3661.

The valuet function is one-to-one, but its range is restricted to [0..86400]. So, it has an inverse function valuet -1(x) that returns: the corresponding time value for x, if x is in [0..86400]; and valuet -1(y), where y = x – floor(x/86400) * 86400, if x is not in [0..86400].

Note: That is, valuet -1(x) is always actually applied to x modulo 86400. For example, valuet -1(3600) will return the time of day that is “01:00:00”, valuet -1(90000) will also return “T01 :00:00”, and valuet -1(-3600) will return the time of day that is “23 :00:00”, treating -3600 seconds as one hour before midnight.

date

Dates in FEEL can be expressed using either a date literal (see grammar rule 65) or the date() built-in function (See 10.3.4.1). A date in the semantic domain is a sequence of numbers for the year, month, day of the month. The year must be in the range [-999,999,999. .999,999,999]. We use boldface date literals to represent values in the semantic domain.

Where necessary, including the valuedt function (see 10.3.2.3.6), a date value is considered to be equivalent to a date time value in which the time of day is UTC midnight (00:00:00).

date-time

Date and time in FEEL can be expressed using either a date time literal (see grammar rule 65) or the date and time() built-in function (See 10.3.2.3.6). We use boldface date and time literals to represent values in the semantic domain.

A date and time in the semantic domain is a sequence of numbers for the year, month, day, hour, minute, second, and optional time offset from Universal Coordinated Time (UTC). The year must be in the range [-999,999,999..999,999,999]. If there is an associated time offset, including 00:00, the date-time value has a UTC form and is comparable to all other date-time values that have UTC forms. If there is no associated time offset, the time is taken to be a local time of day at some location, according to the time zone rules for that location. When the time zone is specified, e.g., using the IANA tz form (see 10.3.4.1), the date-time value may be converted to a UTC form using the time zone rules for that location, if applicable.

Note: projecting timezone rules into the future may only be safe for near-term date-time values.

A date and time d that has a UTC form can be represented as a number of seconds since a reference date and time (called the epoch). We write valuedt(d) to represent the number of seconds between d and the epoch. The valuedt function is one- to-one and so it has an inverse function valuedt -1. E.g., valuedt-1(valuedt(d)) = d. valuedt -1 returns null rather than a date with a year outside the legal range.

days and time duration

Days and time durations in FEEL can be expressed using either a duration literal (see grammar rule 65) or the duration() built-in function (See 10.3.4.1). We use boldface days and time duration literals to represent values in the semantic domain. The literal format of the characters within the quotes of the string literal is defined by the lexical space of the XPath Data Model dayTimeDuration datatype. A days and time duration in the semantic domain is a sequence of numbers for the days, hours, minutes, and seconds of duration, normalized such that the sum of these numbers is minimized. For example, FEEL(duraion("P0DT25H")) = P1DT1H.

The value of a days and time duration can be expressed as a number of seconds. E.g., valuedtd(P1DT1H) = 90000. The valuedtd function is one-to-one and so it has an inverse function valuedtd -1. E.g., valuedtd -1(90000) = P1DT1H.

years and months duration

Years and months durations in FEEL can be expressed using either a duration literal (see grammar rule 65) or the duration() built-in function (See 10.3.4.1). We use boldface years and month duration literals to represent values in the semantic domain. The literal format of the characters within the quotes of the string literal is defined by the lexical space of the XPath Data Model yearMonthDuration datatype. A years and months duration in the semantic domain is a pair of numbers for the years and months of duration, normalized such that the sum of these numbers is minimized. For example, FEEL(duraion("P0Y13M")) = P1Y1M.

The value of a years and months duration can be expressed as a number of months. E.g., valueymd(P1Y1M) = 13. The valueymd function is one-to-one and so it has an inverse function valueymd -1. E.g., valueymd -1(13) = P1Y1M.

Ternary logic

FEEL, like SQL and PMML, uses of ternary logic for truth values. This makes and and or complete functions from *D* x D → *D*. Ternary logic is used in Predictive Modeling Markup Language to model missing data values.

Lists and filters

Lists are immutable and may be nested. The first element of a list L can be accessed using L[1] and the last element can be accessed using L[-1]. The nth element from the beginning can be accessed using L[n], and the nth element from the end can be accessed using L[-n].

If FEEL(L) = L is a list in the FEEL semantic domain, the first element is FEEL(L[1]) = L[1]. If L does not contain n items, then L[n] is null.

L can be filtered with a Boolean expression in square brackets. The expression in square brackets can reference a list element using the name item, unless the list element is a context that contains the key "item". If the list element is a context, then its context entries may be referenced within the filter expression without the 'item.' prefix. For example:

[1, 2, 3, 4][item > 2] = [3, 4]

[ \{x:1, y:2}, \{x:2, y:3} ][x=1] = [\{x:1, y:2}]

The filter expression is evaluated for each item in list, and a list containing only items where the filter expression is true is returned. E.g:

[ \{x:1, y:2}, \{x:null, y:3} ][x < 2] = [\{x:1, y:2}]

The expression to be filtered is subject to implicit conversions (10.3.2.9.4) before the entire expression is evaluated.

For convenience, a selection using the "." operator with a list of contexts on its left hand side returns a list of selections, i.e. FEEL(e.f, c) = [ FEEL(f, c'), FEEL(f, c"), …​ ] where FEEL(e) = [ e', e", …​ ] and c' is c augmented with the context entries of e', c" is c augmented with the context entries of e", etc. For example,

[ \{x:1, y:2}, \{x:2, y:3} ].y = [2,3]

Context

A FEEL context is a partially ordered collection of (key, expression) pairs called context entries. In the syntax, keys can be either names or strings. Keys are mapped to strings in the semantic domain. These strings are distinct within a context. A context in the domain is denoted using bold FEEL syntax with string keys, e.g. \{ "key1" : expr1, "key2" : expr2, …​ }.

The syntax for selecting the value of the entry named key1 from context-valued expression m is m.key1.

If key1 is not a legal name or for whatever reason one wishes to treat the key as a string, the following syntax is allowed: get value(m, "key1 "). Selecting a value by key from context m in the semantic domain is denoted as m.key1 or get value(m, "key1")

To retrieve a list of key,value pairs from a context m, the following built-in function may be used: get entries(m). For example, the following is true:

get entries(\{key1: "value1 "})[key= "key1 "].value = "value1"

An expression in a context entry may not reference the key of the same context entry, but may reference keys (as QNs) from previous context entries in the same context, as well as other values (as QNs) in scope.

These references SHALL be acyclic and form a partial order. The expressions in a context SHALL be evaluated consistent with this partial order.

Ranges

FEEL supports a compact syntax for a range of values, useful in decision table test cells and elsewhere. Ranges can be syntactically represented either:

as a comparison operator and a single endpoint (grammar rule 7.a.)or a pair of endpoints and endpoint inclusivity flags that indicate whether one or both endpoints are included in the range (grammar rule 7.b.); on this case, endpoints must be of equivalent types (see section 10.3.2.9.1for the definition of type equivalence) and the endpoints must be ordered such that range start ⇐ range end.Endpoints can be either a literal or a qualified name of the following types: number, string, date, time, date and time, or duration. The following are examples of valid ranges:

< 10>= date(“2019-03-31”)>= @”2019-03-31”⇐ duration(“PT01H”)⇐ @”PT01H”[ 5 .. 10 ]( birthday .. @”2019-01-01” ) Ranges are mapped into the semantic domain as a typed instance of the range type. If the syntax with a single endpoint and an operator is used, then the other endpoint is undefined (represented by a null value) and the inclusivity flag is set to false. E.g.:

[_Toc87278972 .anchor]#Table 42: Examples of range properties values

Table 13. [_Toc87278986 .anchor]#Table 56: General semantics of addition and subtraction
_ range _ _ start included _ _ start _ _ end _ _ end included _

[1..10]

true

1

10

true

(1..10]

false

1

10

true

⇐ 10

false

null

10

true

1

false

1

null

false

Functions

The FEEL function literal is given by grammar rule 55. Functions can also be specified in DMN via Function Definitions (see 6.3.9). The constructed type (T1, . . . , Tn) → U contains the function values that take arguments of types T1, . . . , Tn and yield results of type U, regardless of the way the function syntax (e.g., FEEL literal or DMN Function Definition). In the case of exactly one argument type TU is a shorthand for (T ) → U.

Relations between types

Every FEEL expression executed in a certain context has a value in D, and every value has a type. The FEEL types are organized as a lattice (see Figure 10‑26), with upper type Any and lower type Null. The lattice determines the conformance of the different types to each other. For example, because comparison is defined only between values with conforming types, you cannot compare a number with a boolean or a string.

We define type(*e)* as the type of the domain element FEEL(*e, *c), where e is an expression defined by grammar rule 1. Literals for numbers, strings, booleans, null, date, time, date and time and duration literals are mapped to the corresponding node in lattice L. Complex expression such as list, contexts and functions are mapped to the corresponding parameterized nodes in lattice L. . For example, see Table 43.

Table 14. [_Toc87278987 .anchor]#Table 57: Specific semantics of addition and subtraction
_ _e __ _ type(*_e)* __

123

number

true

boolean

"abc"

string

date("2017-01-01 ")

date

["a", "b", "c"]

list<string>

["a", true, 123]

list<Any>

[1..10)

range<number>

>= @”201 9-01-01”

range<date>

e

type(e)

\{"name": "Peter", age: 30}

context<”age”: number, “name”:string>

function f(x: number, y: number) x + y

(number, number) → number

DecisionA

where the typeRef of DecisionA is <itemDefinition name="Employee">

<itemComponent name="id">

<typeRef>number</typeRef>

</itemComponent>

<itemComponentname="name"> <typeRef>string</typeRef> </itemComponent>

</itemDefinition>

context<”id”:number, “name”:string>

BkmA

where the encapsulated logic is <encapsulatedLogic>

<formalParameter name="x" typeRef=" number" />

<formalParameter name="y" typeRef=" number" />

<literalExpression typeRef="number"> <text>x + y</text>

</literalExpression>

</encapsulatedLogic>

(number, number) → number

A type expression e defined by grammar rule 54 is mapped to the nodes in the lattice L by function type(*e)* as follows: primitive data type names are mapped to the node with the same name (e.g. string is mapped the string node)

Any is mapped to the node Any*Null is mapped to the node *Null*list< T> is mapped to the *list node with the parameter type(*T)context(k1:T1, …​, kn:Tn> where n≥1 is mapped to the *context node with parameters k1: type(*T1), …​, kn: *type(*Tn)function< T1, …​ Tn> → T is mapped to the *function node with signature type(*T1), …​, *type(*Tn)* → *type(*T)Type names defined in the itemDefinitions section are mapped similarly to the context types (see rule above).If none of the above rules can be applied (e.g. type name does not exist in the decision model) the type expression is semantically incorrect.We define two relations between types:

Equivalence (T ≡ S): Types T and S are interchangeable in all contexts.Conformance (T <:S): An instance of type T can be substituted at each place where an instance of type S is expected.Type Equivalence

The equivalence relationship (≡) between types is defined as follows:

Primitive datatypes are equivalent to themselves, e.g., string ≡ string.Two list types list< T> and list<S> are equivalent iff T is equivalent to S. For example, the types of [“a”, “b”] and [“c”] are equivalent.Two context types context<k1: T1, …​, kn: Tn> and context<l1: S 1, …​, lm: Sm> are equivalent iff n = m and for every ki :Ti there is a unique lj :Sj such that ki = lj and TiSj for i = 1, n. Context types are the types defined via ItemDefinitions or the types associated to FEEL context literals such as \{ “name”: “John”, “age”: 25}.Two function types (T1, …​, Tn) →U and (S1, …​, Sm) →V are equivalent iff n = m, TiSj for i = 1, n and UV.Two range types range< T> and range<S> are equivalent iff T is equivalent to S. For example, the types of [1..10] and [30..40] are equivalent.Type equivalence is transitive: if type1 is equivalent to type2, and type2 is equivalent to type3, then type1 is equivalent to type3.

Type Conformance

The conformance relation (<:) is defined as follows:

Conformance includes equivalence. If TS then T <: SFor every type T, Null <: T <: Any, where Null is the lower type in the lattice and Any the upper type in the lattice.The list type list< T> conforms to list<S> iff T conforms to S.The context type context<k1: T1, …​, kn: Tn> conforms to context<l1: S 1, …​, lm: Sm> iff n ≥ m and for every li : Si there is a unique kj:Tj such that li = kj and Tj <: Si for i = 1, mThe function type (T1, …​, Tn) →U conforms to type (S1, …​, Sm) →V iff n = m, Si <: Ti for i = 1, n and U <: V. The FEEL functions follow the “contravariant function argument type” and “covariant function return type” principles to provide type safety.The range type range< T> conforms to range< S> iff T conforms to S. Type conformance is transitive: if type1 conforms to type2, and type2 conforms to type3 , then type1 conforms to type3.

image

[_Toc87278865 .anchor]#Figure 10‑26: FEEL lattice type

Examples

Let us consider the following ItemDefinitions:

<itemDefinition name="Employee1"> <itemComponent name="id">

<typeRef>number</typeRef> </itemComponent>

<itemComponent name="name"> <typeRef>string</typeRef> </itemComponent>

</itemDefinition>

<itemDefinition name="Employee2"> <itemComponent name="name">

<typeRef>string</typeRef> </itemComponent>

<itemComponent name="id">

<typeRef>number</typeRef>

</itemComponent> </itemDefinition>

<itemDefinition name="Employee3"> <itemComponent name="id">

<typeRef>number</typeRef> </itemComponent>

<itemComponent name="name"> <typeRef>string</typeRef> </itemComponent>

<itemComponent name="age">

<typeRef>number</typeRef> </itemComponent>

</itemDefinition>

<itemDefinition isCollection=”true” name="Employee3List">

<itemComponent name="id">

<typeRef>number</typeRef> </itemComponent>

<itemComponent name="name"> <typeRef>string</typeRef> </itemComponent>

<itemComponent name="age">

<typeRef>number</typeRef> </itemComponent>

</itemDefinition>

and the decisions Decision1 , Decision2, Decision3 and Decision4 with corresponding typeRefs Employee1 , Employee2,

Employee3 and Employee3List.

Table 44 provides examples for equivalence to and conforms to relations.

Table 15. [_Toc87278988 .anchor]#Table 58: General semantics of multiplication and division
_ type1 _ _ type2 _ _ equivalent to _ _ conforms to _

number

number

True

True

string

string

True

True

string

date

False

False

date

date and time

False

False

type(*Decision 1)*

type(*Decision2)*

True

True

type(*Decision1)*

type(*Decision3)*

False

False

type(*Decision3)*

type(*Decision1)*

False

True

type(*Decision 1)*

type(*\{"id": 1, "name " :"Peter"})*

True

True

type(*\{"id": 1, "name " :"Peter"})*

type(*Decision3)*

False

False

type(*\{"id": 1, "name":"Peter", "age": 45})*

type(*Decision1)*

False

True

type(*\{"id": 1, "name":"Peter", "age": 45})*

type(*Decision3)*

True

True

type*([1, 2, 3])*

type*(["1 ", "2", "3"])*

False

False

type*([1, 2, 3])*

type(*Decision3)*

False

False

type(*[\{"id": 1, "name":"Peter", "age": 45}])*

type(*Decision4)*

True

True

type(*Decision4)*

type(*Decision3)*

False

False

type(*function(x:Employee 1 ) →Employee1)*

type(*function(x:Employee 1 ) →Employee1)*

True

True

type(*function(x:Employee 1 ) →Employee1)*

type(*function(x:Employee 1 ) →Employee2)*

True

True

type(*function(x:Employee 1 ) →Employee3)*

type(*function(x:Employee 1 ) →Employee1)*

False

True

type(*function(x:Employee 1 ) →Employee1)*

type(*function(x:Employee 1 ) →Employee1)*

False

False

type( [1..10] )

type( (20..100) )

True

True

type1

type2

equivalent to

conforms to

type( [1..10] )

type( [“a”..”x”] )

False

False

Type conversions

The type of a FEEL expression e is determined from the value e = FEEL(e, s) in the semantic domain, where s is a set of variable bindings (see 10.3.2.11and 10.3.2.12). When an expression appears in a certain context it must be compatible with a type expected in that context, called the target type. After the type of the expression is deduced, an implicit conversion from the type of the expression to the target type can be performed sometimes. If an implicit conversion is mandatory but it cannot be performed the result is null.

There are several possible type conversions:

  • to singleton list:
    When the type of the expression is T and the target type is List<T> the expression is converted to a singleton list.

  • from singleton list:
    When the type of the expression is List<T>, the value of the expression is a singleton list and the target type is T, the expression is converted by unwraping the first element.

  • conforms to:
    When the type of the expression is T1, the target type is T2, and T1 conforms to T2 the value of expression remains unchanged. Otherwise the result is null.

There are several kinds of contexts in which implicit conversions may occur:

  • Filter context (10.3.2.5) in which a filter expression is present. The expression to be filtered is subject to implicit conversion to singleton list.

  • Invocation context (Table 63) in which an argument is bound to a formal parameter of a function. The arguments are subject to implicit conversion from singleton list.

  • Binding contexts in which the value of an expression is bound to a variable with associated type information (e.g. binding actual parameters to formal parameters in an invocation, or binding the result of a decision’s logic to the decision’s output variable). The expression is subject to conforms to conversion.

======= Examples

The table below contains several examples for singleton list conversions.

Table 16. [_Toc87278989 .anchor]#Table 59: Specific semantics of multiplication and division
_ Expression _ _ Conversion _ _ Result _

3[item > 2]

3 is converted to [3] as this a filter context, and an to singleton list is applied

[3]

contains(["foobar"], "of")

["foobar"] is converted to "foobar", as this is an invocation context and from singleton list is applied

false

In the example below, before binding variable decision_003 to value "123" the conversion to the target type (number) fails, hence the variable is bound to null.

<decision name="decision_003" id="_decision_003"> <variable name="decision_003" typeRef="number"/> <literalExpression>

<text>””123”</text>

</literalExpression>

</decision>

Decision Table

The normative notation for decision tables is specified in Clause 8. Each input expression SHALL be a textual expression (grammar rule 2). Each list of input values SHALL be an instance of unary tests (grammar rule 15). The value that is tested is the value of the input expression of the containing InputClause. Each list of output values SHALL be an instance of unary tests (grammar rule 15). The value that is tested is the value of a selected output entry of the containing OutputClause. Each input entry SHALL be an instance of unary tests (grammar rule 15). Rule annotations are ignored in the execution semantics.

The decision table components are shown in Figure 8‑5: Rules as rows – schematic layout, and also correspond to the metamodel in clause 8.3 For convenience, Figure 8‑5 is reproduced here.

Table 17. [_Toc87278990 .anchor]#Table 60: Semantics of exponentiation

information item n*ame*

H

input expression 1

input expression 2

Output label

input value 1a,

input value 1b

input value 2a,

input value 2b

output value 1a,

output value 1b

1

input entry 1.1

input entry 2.1

output entry 1.1

2

input entry 2.2

output entry 1.2

3

input entry 1.2

-

output entry 1.3

The semantics of a decision table is specified by first composing its literal expressions and unary tests into Boolean expressions that are mapped to the semantic domain, and composed into rule matches then rule hits. Finally, some of the decision table output expressions are mapped to the semantic domain and comprise the result of the decision table interpretation. Decision table components are detailed in Table 46.

Table 18. [_Toc87278991 .anchor]#Table 61: Semantics of type-checking
_ Component name ( means optional)* _ _ Description _

input expression

One of the N>=0 input expressions, each a literal expression

input values*

One of the N input values, corresponding to the N input expressions. Each is a unary tests literal (see below).

output values*

A unary tests literal for the output.

(In the event of M>1 output components (see Figure 8‑12), each output component may have its own output values)

rules

a list of R>0 rules. A rule is a list of N input entries followed by M output entries. An input entry is a unary tests literal. An output entry is a literal expression.

hit policy*

one of: "U", "A", “P”, “F”, "R", "O", "C", "C+", "C#", "C<", “C>” (default is "U")

default output value*

The default output value is one of the output values. If M>1, then default output value is a context with entries composed of output component names and output values.

Unary tests (grammar rule 15) are used to represent both input values and input entries. An input expression e is said to satisfy an input entry t (with optional input values v), depending on the syntax of t, as follows:

grammar rule 1 5.a: FEEL(e in (t))=truegrammar rule 1 5.b: FEEL(e in (t))=falsegrammar rule 1 5.c when v is not provided: e != nullgrammar rule 1 5.c when v is provided: FEEL(e in (v))=trueA rule with input entries t1,t2,…​,tN is said to match the input expression list [e1,e2,…​,eN] (with optional input values list [v1,v2, …​vN]) if ei satisfies ti (with optional input values vi) for all i in 1 ..N.

A rule is hit if it is matched and the hit policy indicates that the matched rule’s output value should be included in the decision table result. Each hit results in one output value (multiple outputs are collected into a single context value). Therefore, multiple hits require aggregation.

The hit policy is specified using the initial letter of one of the following boldface policy names.

Single hit policies:

Unique – only a single rule can be matched.Any – multiple rules can match, but they all have the same output,Priority – multiple rules can match, with different outputs. The output that comes first in the supplied output values list is returned,First – return the first match in rule order,Multiple hit policies:

Collect – return a list of the outputs in arbitrary order,Rule order – return a list of outputs in rule order,Output order – return a list of outputs in the order of the output values list The Collect policy may optionally specify an aggregation, as follows:

C+ – return the sum of the outputsC# – return the count of the outputsC< – return the minimum-valued output C> – return the maximum-valued outputThe aggregation is defined using the following built-in functions specified in clause 10.3.4.4: sum, count, minimum, maximum. To reduce complexity, decision tables with compound outputs do not support aggregation and support only the following hit policies: Unique, Any, Priority, First, Collect without operator, and Rule order.

A decision table may have no rule hit for a set of input values. In this case, the result is given by the default output value, or null if no default output value is specified. A complete decision table SHALL NOT specify a default output value.

The semantics of a decision table invocation DTI are as follows:

1. Every rule in the rule list is matched with the input expression list. Matching is unordered.

2. If no rules match,

if a default output value d is specified, DTI=FEEL(d)else DTI=null.3. Else let m be the sublist of rules that match the input expression list. If the hit policy is "First" or "Rule order", order m by rule number.

Let o be a list of output expressions, where the expression at index i is the output expression from rule m[i]. The output expression of a rule in a single output decision table is simply the rule’s output entry. The output expression of a multiple output decision table is a context with entries composed from the output names and the rule’s corresponding output entries. If the hit policy is "Output order", the decision table SHALL be single output and o is ordered consistent with the order of the output values. Rule annotations are ignored for purposes of determining the expression value of a decision table.If a multiple hit policy is specified, DTI=FEEL(aggregation(o)), where aggregation is one of the built-in functions sum, count, minimum as specified in clause 10.3.4.4.else DTI=FEEL(o[1]).Scope and context stack

A FEEL expression e is always evaluated in a well-defined set of name bindings that are used to resolve QNs in e. This set of name bindings is called the scope of e. Scope is modeled as a list of contexts. A scope s contains the contexts with entries that are in scope for e. The last context in s is the built-in context. Next to last in s is the global context. The first context in s is the context immediately containing e (if any). Next are enclosing contexts of e (if any).

The QN of e is the QN of the first context in s appended with .N, where N is the name of entry in the first context of s containing e. QNs in e are resolved by looking through the contexts in s from first to last.

Local context

If e denotes the value of a context entry of context m, then m is the local context for e, and m is the first element of s. Otherwise, e has no local context and the first element of s is the global context, or in some cases explained later, the first element of s is a special context.

All of the entries of m are in-scope for e, but the depends on graph SHALL be acyclic. This provides a simple solution to the problem of the confusing definition above: if m is the result of evaluating the context expression m that contains e, how can we know it in order to evaluate e? Simply evaluate the context entries in depends on order.

Global context

The global context is a context created before the evaluation of e and contains names and values for the variables defined outside expression e that are accessible in e. For example, when e is the body of a decision D, the global context contains entries for the information requirements and knowledge requirements of D (i.e., names and logic of the business knowledge models, decisions and decision services required by D).

Built-in context

The built-in context contains all the built-in functions.

Special context

Some FEEL expressions are interpreted in a special context that is pushed on the front of s. For example, a filter expression is repeatedly executed with special first context containing the name 'item' bound to successive list elements. A function is executed with a special first context containing argument name→value mappings.

Qualified names (QNs) in FEEL expressions are interpreted relative to s. The meaning of a FEEL expression e in scope s is denoted as FEEL(*e, *s). We can also say that e evaluates to e in scope s, or e = FEEL(*e, *s). Note that e and s are elements of the FEEL domain. s is a list of contexts.

Mapping between FEEL and other domains

A FEEL expression e denotes a value e in the semantic domain. Some kinds of values can be passed between FEEL and external Java methods, between FEEL and external PMML models, and between FEEL and XML, as summarized in Table 47. An empty cell means that no mapping is defined.

Table 19. [_Toc87278992 .anchor]#Table 62: Semantics of negative numbers
_ _FEEL value __ _ _Java __ _ _XML __ _ _PMML __

number

java.math.BigDecimal

decimal

decimal, PROB-NUMBER,
PERCENTAGE-NUMBER

integer

integer , INT-NUMBER

double

double, REAL-NUMBER

string

java.lang.String

string

string, FIELD-NAME

date, time, date and time

javax.xml.datatype. XMLGregorianCalendar

date, dateTime, time, dateTimestamp

date, dateTime, time conversion required for dateDaysSince, et. al.

duration

javax.xml.datatype. Duration

yearMonthDuration, dayTimeDuration

boolean

java.lang.Boolean

boolean

boolean

list

java.util.List

contain multiple child elements

array (homogeneous)

context

java.util.Map

contain attributes and child elements

Sometimes we do not want to evaluate a FEEL expression e, we just want to know the type of e*. Note that if e has QNs, then a context may be needed for type inference. We write *type(*e)* as the type of the domain element FEEL(*e, *c).

Functions Seamantics

FEEL functions can be:

built-in, e.g.,

sum (see clause 10.3.4.4), oruser-defined, e.g.,
function(age) age < 21
, orexternally defined, e.g.,
function(angle) external \{
java: \{
class: “java.lang.Math ”,
method signature: “cos(double)”
}}
Built-in Functions

The built-in functions are described in detail in section 10.3.4. In particular, function signatures and parameter domains are specified. Some functions have more than one signature.

Built-in functions are invoked using the same syntax as other functions (grammar rule 40). The actual parameters must conform to the parameter domains in at least one signature before or after applying implicit conversions, or the result of the invocation is null.

User-defined functions

User-defined functions (grammar rule 55) have the form

function(X1, …​ Xn) body

The terms X1, …​ Xn are formal parameters. Each formal parameter has the form ni or ni :_ti_, where the ni are the parameter names and ti are their types. If the type isn’t specified, Any is assumed. The meaning of FEEL(function(X1, …​ Xn) body, s) is an element in the FEEL semantic domain that we denote as function(argument list: [*X1, …​ Xn], body:* body*, scope: s)* (shortened to f below). FEEL functions are lexical closures, i.e., the body is an expression that references the formal parameters and any other names in scope s.

User-defined functions are invoked using the same syntax as other functions (grammar rule 38). The meaning of an invocation f(n1:e1,…​,nn:en) in scope s is FEEL(f, s) applied to arguments n1:FEEL(e1, s)…​ ,nn:FEEL(en, s). This can also be written as f(n1:e1…​ ,*n*n:*e*n).

The arguments n1:e1…​ ,*n*n:*e*n conform to the argument list [*X1, …​ Xn]* if type(ei) conforms to ti before or after applying implicit conversions or ti is not specified in Xi, for all i in 1. .n. The result of applying f to the interpreted arguments n1:e1…​ ,*n*n:*e*n is determined as follows. If f is not a function, or if the arguments do not conform to the argument list, the result of the invocation is null. Otherwise, let c be a context with entries n1:e1…​ ,*n*n:*e*n. The result of the invocation is FEEL(body, s’*), where *s' = insert before(s, 1, c) (see 10.3.4.4).

Invocable elements (Business Knowledge Models or Decision Services) are invoked using the same syntax as other functions (grammar rule 38). An Invocable is equivalent to a FEEL function whose parameters are the invocable’s inputs (see 10.4)

Externally-defined functions

FEEL externally-defined functions have the following form
function (X1, …​ Xn) external mapping-information

Mapping-information is a context that SHALL have one of the following forms:

\{

java: \{class: class-name, method signature: method-signature}

}

or

\{

pmml: \{document: IRI, model: model-name}

}

The meaning of an externally defined function is an element in the semantic domain that we denote as function(argument list: [*X1, …​ Xn], external: mapping-information)*.

The java form of the mapping information indicates that the external function is to be accessed as a method on a Java class. The class-name SHALL be the string name of a Java class on the classpath. Classpath configuration is implementation-defined. The method-signature SHALL be a string consisting of the name of a public static method in the named class, followed by an argument list containing only Java argument type names. The argument type information SHOULD be used to resolve overloaded methods and MAY be used to detect out-of-domain errors before runtime.

The pmml form of the mapping information indicates that the external function is to be accessed as a PMML model. The IRI SHALL be the resource identifier for a PMML document. The model-name is optional. If the model-name is specified, it SHALL be the name of a model in the document to which the IRI refers. If no model-name is specified, the external function SHALL be the first model in the document.

When an externally-defined function is invoked, actual argument values and result value are converted when possible using the type mapping table for Java or PMML (see Table 47). When a conversion is not possible, null is substituted. If a result cannot be obtained, e.g. an exception is thrown, the result of the invocation is null. If the externally-defined function is of type PMML, and PMML invocation results in a single predictor output, the result of the externally-defined function is the single predictor output’s value.

Passing parameter values to the external method or model requires knowing the expected parameter types. For Java, this information is obtained using reflection. For PMML, this information is obtained from the mining schema and data dictionary elements associated with independent variables of the selected model.

Note that DMN does not completely define the semantics of a Decision Model that uses externally-defined functions. Externally-defined functions SHOULD have no side-effects and be deterministic.

Function name

To name a function, define it as a context entry. For example:

\{

isPositive : function(x) x > 0,

isNotNegative : function(x) isPositive(x+ 1), result: isNotNegative(0)

}

Positional and named parameters

An invocation of any FEEL function (built-in, user-defined, or externally-defined) can use positional parameters or named parameters. If positional, all parameters SHALL be supplied. If named, unsupplied parameters are bound to null.

For loop expression

The for loop expression iterates over lists of elements or ranges of numbers. The general syntax is:

for i1 in ic1 [, i2 in ic2 [, …​]] return e

where:

ic1, ic2, …​, icn are iteration contextsi1, i2, …​, in are variables bound to each element in the iteration contexte is the return expressionAn iteration context may either be an expression that returns a list of elements, or two expressions that return integers connected by “..”. Examples of valid iteration contexts are:

[ 1, 2, 3]a list1..1050..40x..x+10A for loop expression will iterate over each element in the iteration context, binding the element to the corresponding variable in and evaluating the expression e in that scope.

When the iteration context is a range of numbers, the for loop expression will iterate over the range incrementing or decrementing the value of in by 1, depending if the range is ascendant (when the resulting integer from the first expression is lower than the second) or descendant (when the resulting integer from the first expression is higher than the second).

The result of the for loop expression is a list containing the result of the evaluation of the expression e for each individual iteration in order.

The expression e may also reference an implicitly defined variable called “partial” that is a list containing all the results of the previous iterations of the expression. The variable “partial” is immutable. E.g.: to calculate the factorial list of numbers, from 0 to N, where N is a non-negative integer, one may write:

for i in 0..N return if i = 0 then 1 else i * partial[-1]

When multiple iteration contexts are defined in the same for loop expression, the resulting iteration is a cross-product of the elements of the iteration contexts. The iteration order is from the inner iteration context to the outer iteration context.

E.g., the result of the following for loop expression is:

for i in [i1,i2], j in [j1j2] return e *= [ r1, r2, r3, r4 ]*

Where:

r1 = FEEL( e, \{ i: i1, j: j1, partial:[], …​ } )

r2 = FEEL( e, \{ i: i1, j: j2, partial:[r1], …​ )

r3 = FEEL( e, \{ i: i2, j: j1, partial:[r1,r2], …​ } )

r4 = FEEL( e, \{ i: i2, j: j2, partial:[r1,r2,r3], …​ } )

Semantic mappings

The meaning of each substantive grammar rule is given below by mapping the syntax to a value in the semantic domain. The value may depend on certain input values, themselves having been mapped to the semantic domain. The input values may have to obey additional constraints. The input domain(s) may be a subset of the semantic domain. Inputs outside of their domain result in a null value, unless the implicit conversion from singleton list (10.3.2.9.4) can be applied.

Table 20. [_Toc87278993 .anchor]#Table 63: Semantics of invocation
_ Grammar Rule _ _ FEEL Syntax _ _ Mapped to Domain _

55

function(n1, …​nN) e

function(argument list: [*n1, …​ nN], body:* e*, scope: s)*

55

function(n1, …​nN) external e

function(argument list: [*n1, …​ nN], external: e)*

See 10.3.2.7.

Table 21. [_Toc87278994 .anchor]#Table 64: General semantics of properties
_ Grammar Rule _ _ FEEL Syntax _ _ Mapped to Domain _

44

for i1 in ic1, i2 in ic2, …​ return e

[ FEEL(*e, *s'), FEEL(*e, *si, …​ ]

45

if e1 then e2 else e3

if FEEL(*e1) is true then FEEL(e2) else FEEL(e3)*

46

some n1 in e1, n2 in e2, …​ satisfies e

false or FEEL(*e, *s') or FEEL(*e, *s") or …​

46

every n 1 in e 1, n2 in e2, …​ satisfies e

true and FEEL(*e, *s') and FEEL(*e, *s") and …​

47

e1 or e2 or …​

FEEL(*e1) or FEEL(e2) or* …​

48

e1 and e2 and …​

FEEL(*e1) and FEEL(e2) and* …​

49.a

e = null

FEEL(*e) is null*

49.a

null = e

FEEL(*e) is null*

49.a

e != null

FEEL(*e) is not null*

49.a

null != e

FEEL(e) is not null

Notice that we use bold syntax to denote contexts, lists, conjunctions, disjunctions, conditional expressions, true, false, and null in the FEEL domain.

The meaning of the conjunction a and b and the disjunction a or b is defined by ternary logic. Because these are total functions, the input can be true, false, or otherwise (meaning any element of D other than true or false).

A conditional if a then b else c is equal to b if a is true, and equal to c otherwise.

s' is the scope s with a special first context containing keys n1, n2, etc. bound to the first element of the Cartesian product of FEEL(e1*) x* FEEL(e2*) x …​, s"* is s with a special first context containing keys bound to the second element of the Cartesian product, etc. When the Cartesian product is empty, the some …​ satisfies quantifier returns false and the every …​ satisfies quantifier returns true.

Table 22. [_Toc87278995 .anchor]#Table 65: List of properties per type
_ a _ _ b _ _ a and b _ _ a or b _

true

true

true

true

true

false

false

true

true

otherwise

null

true

false

true

false

true

false

false

false

false

false

otherwise

false

null

otherwise

true

null

true

otherwise

false

false

null

otherwise

otherwise

null

null

Negation is accomplished using the built-in function not. The ternary logic is as shown in Table 51.

Table 23. [_Toc87278996 .anchor]#Table 66: Specific semantics of date, time and duration properties
_ a _ _ not(a) _

true

false

false

true

otherwise

null

Equality and inequality map to several kind- and datatype-specific tests, as shown in Table 52, Table 53 and Table 54. By definition, FEEL(e1 != e2) is FEEL(not(e 1= e2)). The other comparison operators are defined only for the datatypes listed in Table 54. Note that Table 54 defines only ‘<’; ‘>’ is similar to ‘<’ and is omitted for brevity; e1⇐e2 is defined as e1< e2 or e1= e2.

Table 24. [_Toc87278997 .anchor]#Table 67: Specific semantics of range properties
_ Grammar Rule _ _ FEEL Syntax _ _ Input Domain _ _ Result _

49.a

e1 = e2

e1 and e2 must both be of the same kind/datatype – both numbers, both strings, etc.

See below

49.a

e1 < e2

e1 and e2 must both be of the same kind/datatype – both numbers, both strings, etc.

See below

Table 25. [_Toc87278998 .anchor]#Table 68: Semantics of lists
_ kind/datatype _ _ _e1 = e2 __

list

lists must be same length N and e1[i] = e2[i] for 1 ≤ i ≤ N.

context

contexts must have same set of keys K and e1.k = e2.k for every k in K

range

the ranges must specify the same endpoint(s) and the same comparison operator or endpoint inclusivity flag.

function

internal functions must have the same parameters, body, and scope. Externally defined functions must have the same parameters and external mapping information.

number

value(e1) = value(e2). Value is defined in 10.3.2.3.1. Precision is not considered.

string

e1 is the same sequence of characters as e2

date

value(e1) = value(e2). Value is defined in 10.3.2.3.5

date and time

value(e1) = value(e2). Value is defined in 10.3.2.3.6

time

value(e1) = value(e2). Value is defined in 10.3.2.3.4.

days and time duration

value(e1) = value(e2). Value is defined in 10.3.2.3.7

years and months duration

value(e1) = value(e2). Value is defined in 10.3.2.3.8.

boolean

e1 and e2 must both be true or both be false

Table 26. [_Toc87278999 .anchor]#Table 69: Semantics of contexts
_ datatype _ _ _e1 < e2 __

number

value(e1) < value(e2). value is defined in 10.3.2.3.1. Precision is not considered.

string

sequence of characters e1 is lexicographically less than the sequence of characters e2. I.e., the sequences are padded to the same length if needed with \u0 characters, stripped of common prefix characters, and then the first character in each sequence is compared.

date

e1 < e2 if the year value of e1 < the year value of e2 e1 < e2 if the year values are equal and the month value of e1 < the month value of e2 e1 < e2 if the year and month values are equal and the day value of e1 < the day value of e2

date and time

valuedt(e1) < valuedt(e2). valuedt is defined in 10.3.2.3.5. If one input has a null timezone offset, that input uses the timezone offset of the other input.

time

valuet(e1) < valuet(e2). valuet is defined in 10.3.2.3.4. If one input has a null timezone offset, that input uses the timezone offset of the other input.

days and time duration

valuedtd(e1) < valuedtd(e2). valuedtd is defined in 10.3.2.3.7.

years and months duration

valueymd(e1) < valueymd(e2). valueymd is defined in 10.3.2.3.8.

 +
FEEL supports additional syntactic sugar for comparison. Note that Grammar Rules (clause 10.3.1.2) are used in decision table condition cells. These decision table syntaxes are defined in *Table _55_*.
Table 27. [_Toc87279000 .anchor]#Table 70: Semantics of XML elements
_ Grammar Rule _ _ FEEL Syntax _ _ Equivalent FEEL Syntax _ _ applicability _

49.b

e1 between e2 and e3

e1 >= e2 and e1 ⇐ e3

49.c

e1 in [e2,e3, …​ ]

e1 = e2 or e1 = e3 or…​

e2 and e3 are endpoints

49.c

e1 in [e2,e3, …​ ]

e1 in e2 or e1 in e3 or…​

e2 and e3 are ranges

49.c

e1 in ⇐e2

e1 ⇐ e2

49.c

e1 in <e2

e1 < e2

49.c

e1 in >=e2

e1 >= e2

49.c

e1 in >e2

e1 > e2

49.c

e1 in (e2..e3)

e1 > e2 and e1<e3

49.c

e1 in (e2..e3]

e1 > e2 and e1⇐e3

49.c

e1 in [e2..e3)

e1 >= e2 and e1<e3

49.c

e1 in [e2..e3]

e1 >= e2 and e1⇐e3

49.c

e1 in e2

e1 = e2

e2 is a qualified name that does not evaluate to a list

49.c

e1 in e2

list contains( e2, e1 )

e1 is a simple value that is not a list and e2 is a qualified name that evaluates to a list

49.c

e1 in e2

\{ ? : e1, r : e2 }.r

e2 is a boolean expression that uses the special variable “?”

Addition and subtraction are defined in Table 56 and Table 57. Note that if input values are not of the listed types, the result is null.

Table 28. [_Toc87279001 .anchor]#Table 71: Semantics of XML values
_ Grammar Rule _ FEEL _ Input Domain and Result _

19

e1 + e2

See below

20

e1 – e2

See below

date time string – a string value consisting of a date string value, as specified above, optionally followed by the character "T" followed by a time string value as specified above.

duration string – a string value in the lexical space of the xs:dayTimeDuration or xs:yearMonthDuration datatypes specified by the XQuery 1.0 and XPath 2.0 Data Model. [_Toc87279002 .anchor]#Table 72: Semantics of conversion functions

_ type(e1) _ _ type(e2) _ _ _e1 + e2, e1 – e2 __ _ result type _

number

number

Let e1=(p1,s1) and e2=(p2,s2) as defined in 10.3.2.3.1. If value(p1,s1) +/- value(p2,s2) requires a scale outside the range of valid scales, the result is null. Else the result is (p,s) such that

number

value(p,s) = value(p1,s1) +/- value(p2,s2) + ε

s ≤ max(s1,s2)

s is maximized subject to the limitation that p has 34 digits or less

ε is a possible rounding error.

date and time

date and time

Addition is undefined. Subtraction is defined as valuedtj1 (valuedt(e1)-valuedt(e2)), where valuedt is defined in 10.3.2.3.5 and valuedtj1 is defined in

days and time duration

10.3.2.3.7. In case either value is of type date, it is implicitly converted into a date and time with time of day of UTC midnight ("00:00:00") as defined in

10.3.2.3.6. Subtraction requires either both values to have a timezone or both not to have a timezone.

Subtraction is undefined for the case where only one of the values has a timezone.

time

time

Addition is undefined. Subtraction is defined as valuedtd-1 (valuet(e1)-valuet(e2)) where valuet is defined in 10.3.2.3.4 and valuedtd -1 is defined in 10.3.2.3.7.

days and time duration

years and months duration

years and months duration

valueymd-1(valueymd(e1) +/- valueymd(e2)) where valueymd and valueymd -1 is defined in 10.3.2.3.8.

years and months duration

days and time duration

days and time duration

valuedtd -1(valuedtd(e1) +/- valuedtd(e2)) where valuedtd and valuedtd-1 is defined in 10.3.2.3.7.

days and time duration

date and time

years and months duration

date and time (date(e1.year +/– e2.years + floor((e1.month +/– e2.months)/12),

e1.month +/– e2.months – floore1.month +/– e2.months)/12) * 12, e1.day), time(e1,

where the named properties are as defined in Table 65 below, and the date, date and time, time and floor functions are as defined in 10.3.4, valuedt and valuedt -1 is defined in 10.3.2.3.5 and valueymd is defined in 10.3.2.3.8.

date and time

years and months duration

date and time

Subtraction is undefined. Addition is commutative and is defined by the previous rule.

date and time

date and time

days and time duration

valuedt -1(valuedt(e1) +/- valuedtd(e2)) where valuedt and valuedt -1 is defined in 10.3.2.3.5 and valuedtd is defined in 10.3.2.3.7.

date and time

days and time duration

date and time

Subtraction is undefined. Addition is commutative and is defined by the previous rule.

date and time

time

days and time duration

valuet -1(valuet(e1) +/- valuedtd(e2)) where valuet and valuet -1 are defined in 10.3.2.3.4 and valuedtd is defined in 10.3.2.3.7.

time

days and time duration

time

Subtraction is undefined. Addition is commutative and is defined by the previous rule.

time

string

string

Subtraction is undefined. Addition concatenates the strings. The result is a string containing the sequence of characters in e1 followed by the sequence of characters in e2.

string

date

years and months duration

date( e1.year +/– e2.years + floor((e1.month +/– e2.months)/12), e1.month +/– e2.months – floor((e1.month +/– e2.months)/12) * 12, e1.day ), where the named properties are as defined in Table 65 below, and the date and floor functions are as defined in 10.3.4.

date

years and months duration

date

Subtraction is undefined. Addition is commutative and is defined by the previous rule.

date

date

days and time duration

date(valuedt-1 (valuedt(e1) +/- valuedtd(e2))) where valuedt and valuedt-1 is defined in 10.3.2.3.5 and valuedtd is defined in 10.3.2.3.7.

date

days and time duration

date

Subtraction is undefined. Addition is commutative and is defined by the previous rule.

date

Multiplication and division are defined in Table 58 and Table 59. Note that if input values are not of the listed types, the result is null.

Table 29. [_Toc87279003 .anchor]#Table 73: Semantics of Boolean functions
_ Grammar Rule _ FEEL _ Input Domain and Result _

21

e1 * e2

See below

22

e1 / e2

See below

Table 30. [_Toc87279004 .anchor]#Table 74: Semantics of string functions
_ type(e1) _ _ type(e2) _ e1 * e2 e1 / e2 _ result type _

number e1=(p1,s1)

number e2=(p2,s2)

If value(p1,s1) * value(p2,s2) requires a scale outside the range of valid scales, the result is null. Else the result is (p,s) such that

value(p,s) = value(p1,s1) * value(p2,s2) + εs ≤ s1+s2s is maximized subject to the limitation that p has 34 digits or lessε is a possible rounding errorIf value(p2,s2)=0 or value(p1,s1) / value(p2,s2) requires a scale outside the range of valid scales, the result is null. Else the result is (p,s) such that

value(p,s) = value(p1,s1) / value(p2,s2) + εs ≤ s1-s2s is maximized subject to the limitation that p has 34 digits or less

ε is a possible rounding errornumber

years and months duration

number

valueymd -1(valueymd(e1) * value(e2)) where valueymd and valueymd -1 are defined in 10.3.2.3.8

If value(e2)=0, the result is null. Else the result is valueymd- 1(valueymd(e1) / value(e2)) where valueymd and valueymd-1 are defined in 10.3.2.3.8.

years and months
duration

number

years and months duration

See above, reversing e1 and e2

Not allowed

years and months
duration

years and months duration

years and months duration

Not allowed

If valueymd(e2)=0, the result is null. Else the result is valueymd(e1) / valueymd(e2) where valueymd is defined in 10.3.2.3.8.

number

days and time duration

number

valuedtd-1(valuedtd(e1) * value(e2)) where valuedtd and valuedtd -1 are defined in 10.3.2.3.7.

If value(e2)=0, the result is null.

Else the result is valuedtd 1(valuedtd(e1) * value(e2)) where valuedtd and valuedtd -1 are

defined in 10.3.2.3.7.

days and time duration

number

days and time duration

See above, reversing e1 and e2

Not allowed

days and time duration

days and time duration

days and time

duration

Not allowed

If valuedtd(e2)=0, the result is null. Else the result is valuedtd(e1) / valuedtd(e2) where valuedtd is defined in 10.3.2.3.7.

number

Table 31. [_Toc87279005 .anchor]#Table 75: Semantics of list functions
_ Grammar Rule _ _ FEEL Syntax _ _ Input Domain _ _ Result _

23

e1 ** e2

type(e1) is number. value(e2) is a number in the range

[-999,999,999..999,999,999].

If value(e1)value(e2 ) requires a scale that is out of range, the result is null. Else the result is (p,s) such that

value(p,s)= value(e1)value(e2) + εp is limited to 34 digitsε is rounding error

Type-checking is defined in Table 61. Note that type is not mapped to the domain, and null is the only value in the Null type (see 10.3.2.1).

Before evaluating the instance of operator both operands are mapped to the type lattice L (see 10.3.2.9).

Table 32. [_Toc87279006 .anchor]#Table 76: Semantics of numeric functions
_ Grammar Rule _ _ FEEL Syntax _ _ Mapped to Domain _ _ Examples _

51

e1 instance of e2

If e2 cannot be mapped to a node in the lattice L, the result is null.
If e1 is null and type(*e2)* is Null, the result is true.
If type(*e1)* conforms to type(*e2)* (see section 10.3.2.9) and e1 is
not null, the result is true. Otherwise the result is false.

[123] instance of list<number> is true "abc" instance of string is true

123 instance of string is false

123 instance of list is null as a list type requires parameters (see rule 54).

Negative numbers are defined in Table 62.

Table 33. [_Toc87279007 .anchor]#Table 77: Semantics of date and time functions
_ Grammar Rule _ _ FEEL Syntax _ _ Equivalent FEEL Syntax _

24

-e

0-e

Invocation is defined in Table 63. An invocation can use positional arguments or named arguments. If positional, all arguments must be supplied. If named, unsupplied arguments are bound to null. Note that e can be a user-defined function, a user-defined external function, or a built-in function. The arguments are subject to implicit conversions (10.3.2.9.4). If the argument types before or after conversion do not conform to the corresponding parameter types, the result of the invocation is null.

Table 34. [_Toc87279008 .anchor]#Table 78: Semantics of range functions
_ Grammar Rule _ _ FEEL _ _ Mapped to Domain _ _ Applicability _

38,

39,

42

e(e1,..)

e(e1,…​)

e is a function with matching arity and conforming parameter types

38,

39,

40,

41

e(n1:e1,…​)

e(*n1:e1,…​)*

e is a function with matching parameter names and conforming parameter types

Properties are defined in Table 64 and Table 65. If type(*e)* is date and time, time, or duration, and name is a property name, then the meaning is given by Table 65 and Table 66. For example, FEEL(date and time("2012-03-07Z").year) = 2012.

Table 35. [_Toc87279009 .anchor]#Table 79: Temporal built-in functions
_ Grammar Rule _ _ FEEL _ _ Mapped to Domain _ _ Applicability _

18

e.name

e."name"

type(e) is a context

18

e.name

see below

type(e) is a date/time/duration

Table 36. [_Toc87279010 .anchor]#Table 80: Semantics of sort functions
_ type(_e) __ _ _e . name __ _ name = _

date

result is the named component of the date object e. Valid names are shown to the right.

year, month, day, weekday

date and time

result is the named component of the date and time object e. Valid names are shown to the right.

year, month, day, weekday, hour, minute, second, time offset, timezone

time

result is the named component of the time object e. Valid names are shown to the right

hour, minute, second, time offset, timezone

years and months duration

result is the named component of the years and months duration object e. Valid names are shown to the right.

years, months

days and time duration

result is the named component of the days and time duration object e. Valid names are shown to the right.

days, hours, minutes, seconds

range

result is the named component of the range object e. Valid names are shown to the right.

start, end, start included, end included

Table 37. [_Toc87279011 .anchor]#Table 81: Semantics of Context functions
_ name _ _ _type(name) __ _ description _

year

number

The year number as an integer in the interval [-999,999,999 .. 999,999,999]

month

number

The month number as an integer in the interval [1..12], where 1 is January and 12 is December

day

number

The day of the month as an integer in the interval [1 ..31]

weekday

number

The day of the week as an integer in the interval [1. .7] where 1 is Monday and 7 is Sunday (compliant with the definition in ISO 8601)

hour

number

The hour of the day as an integer in the interval [0..23]

minute

number

The minute of the hour as an integer in the interval [0..59]

second

number

The second of the minute as a decimal in the interval [0. .60)

time offset

days and time duration

The duration offset corresponding to the timezone the date or date and time value represents. The time offset duration must be in the interval [duration(“-PT14H”)..duration(“PT14H”)] as per the XML Schema Part 2 dateTime datatype. The time offset property returns null when the object does not have a time offset set.

timezone

string

The timezone identifier as defined in the IANA Time Zones database. The timezone property returns null when the object does not have an IANA timezone defined.

name

type(name)

description

years

number

The normalized years component of a years and months duration value as an integer. This property returns null when invoked on a days and time duration value.

months

number

The normalized months component of a years and months duration value. Since the value is normalized, this property must return an integer in the interval [0.. 11]. This property returns null when invoked on a days and time duration value.

days

number

The normalized days component of a days and time duration value as an integer. This property returns null when invoked on a years and months duration value.

Hours

number

The normalized hours component of a days and time duration value. Since the value is normalized, this property must return an integer in the interval [0..23]. This property returns null when invoked on a years and months duration value.

minutes

number

The normalized minutes component of a days and time duration value. Since the value is normalized, this property must return an integer in the interval [0..59]. This property returns null when invoked on a years and months duration value.

seconds

number

The normalized minutes component of a days and time duration value. Since the value is normalized, this property must return a decimal in the interval [0..60). This property returns null when invoked on a years and months duration value.

Table 38. [_Toc87279012 .anchor]#Table82: Miscellaneous functions
_ name _ _ type(name) _ _ description _

start

Type of the start endpoint of the range

the start endpoint of the range

end

Type of the end endpoint of the range

the end endpoint of the range

start included

boolean

true if the start endpoint is included in the range

end included

boolean

true if the end endpoint is included in the range

Lists are defined in Table 68.

Table 39. [_Toc87279013 .anchor]#Table 83: Context attributes and model association
_ Grammar Rule _ _ FEEL Syntax _ _ Mapped to Domain (scope s) _ _ Applicability _

54

e1[e2]

e1[e2]

e1 is a list and e2 is an integer (0 scale number)

54

e1[e2]

e 1

e1 is not a list and not null and value(e2) = 1

54

e1[e2]

list of items e such that i is in e iff i is in e1 and FEEL(e2, s') is true, where s' is the scope s with a special first context containing the context entry ("item", i) and if i is a context, the special context also contains all the context entries of i.

e1 is a list and type(FEEL(e2, s')) is boolean

54

e1[e2]

[e1] if FEEL(e2, s') is true, where s' is the scope s with a special first context containing the context entry ("item", e1) and if e1 is a context, the special context also contains all the context entries of e1. Else [].

e1 is not a list and not null and type(FEEL(e2, s')) is boolean

Contexts are defined in Table 69.

Table 40. [_Toc87279014 .anchor]#Table 84: ContextEntry attributes and model associations
_ Grammar Rule _ _ FEEL Syntax _ _ Mapped to Domain (scope s) _

\{ n1 : e1, n2 : e2, …​}

\{ "n1": FEEL(e1, s1), "n2": FEEL(e2, s2), …​} such that the si are all s with a special first context ci containing a

\{ "n1" : e1, "n2" : e2, …​}

57

subset of the entries of this result context. If ci contains
the entry for nj, then cj does not contain the entry for ni.

54

[e1, e2, …​]

[ FEEL(e1), FEEL(e2), …​]

Error Handling

When a built-in function encounters input that is outside its defined domain, the function SHOULD report or log diagnostic information if appropriate, and SHALL return null.

XML Data

FEEL supports XML Data in the FEEL context by mapping XML Data into the FEEL Semantic Domain. Let XE(e, p) be a function mapping an XML element e and a parent FEEL context p to a FEEL context , as defined in the following tables. XE makes use of another mapping function, XV(v), that maps an XML value v to the FEEL semantic domain.

XML namespace semantics are not supported by the mappings. For example, given the namespace prefix declarations xmlns:p1= "http://example.org/foobar" and xmlns:p2= "http://example. org/foobar", the tags p1:myElement and p2:myElement are the same element using XML namespace semantics but are different using XML without namespace semantics.

Semantic mapping for XML elements (XE)

Table 70, e is the name of an XML element, a is the name of one of its attributes, c is a child element, and v is a value. The parent context p is initially empty.

Table 41. [_Toc87279015 .anchor]#Table 85: FunctionDefinition attributes and model associations
_ XML _ _ context entry in p _ _ Remark _

<e />

"e" : null

empty element → null-valued entry in p

<q:e />

"e" : null

namespaces are ignored.

<e>v</e>

"e":XV(v)

unrepeated element without attributes

<e>v1</e> <e>v2</e>

"e": [ XV(v1), XV(v2) ]

repeating element without attributes

<e a="v"/>

<c1>v1</c1>

<cn>v2</cn><cn>v3</cn> </e>

"e": \{ "a": XV(v),

"c1": XV(v1),

"cn": [ XV(v2), XV(v3) ]

}

An element containing attributes or child elements → context

<e a="v1">v2</e>

"e": \{ "@a": XV(v1), "$content": XV(v2) }

v2 is contained in a generated $content entry

An entry in the context entry in p column such as "e" : null indicates a context entry with string key "e" and value null. The context entries are contained by context p that corresponds to the containing XML element, or to the XML document itself.

The mapping does not replace namespace prefixes with the namespace IRIs. FEEL requires only that keys within a context be distinct, and the namespace prefixes are sufficient.

Semantic mapping for XML values (XV)

If an XML document was parsed with a schema, then some atomic values may have a datatype other than string. Table 71defines how a typed XML value v is mapped to FEEL.

Table 42. [_Toc87279016 .anchor]#Table 86: List attributes and model associations
_ Type of _v __ _ FEEL Semantic Domain _

number

FEEL(v)

string

FEEL("v")

date

FEEL(date("v"))

dateTime

FEEL(date and time("v"))

time

FEEL(time("v"))

duration

FEEL(duration("v"))

list, e.g. "v1 v2"

[ XV(v1), XV(v2) ]

element

XE(v)

XML example

The following schema and instance are equivalent to the following FEEL:

schema

elementFormDefault="qualified">

<xsd:element name="Context">

<xsd :complexType> <xsd:sequence>

<xsd:element name="Employee">

<xsd:complexType> <xsd:sequence>

<xsd :element na me="sala ry" type="xsd :deci ma l"/>

</xsd :seq uence> </xsd :complexType> </xsd:element>

<xsd:element name="Customer" maxOccurs="unbounded">

<xsd:complexType> <xsd:sequence>

<xsd :element na me="loya lty_level" type="xsd :stri ng"/>

<xsd :element na me="credit_li mit" type="xsd :decima l"/>

</xsd :seq uence>

</xsd :complexType>

</xsd:element>

</xsd:sequence> </xsd :complexType> </xsd:element>

</xsd:schema>

instance

<tns:Employee>

<tns:salary>13000</tns:salary>

</tns:Employee>

<Customer>

<loyalty_level>gold</loyalty_level>

<credit_limit>10000</credit_limit>

</Customer>

<Customer>

<loyalty_level>gold</loyalty_level>

<credit_limit>20000</credit_limit>

</Customer> <Customer> <loya lty_level>si lver</loya lty_level>

<credit_limit>5000</credit_limit>

</Customer>

</Context>

equivalent FEEL boxed context
Table 43. [_Toc87279017 .anchor]#Table 87: Relation attributes and model associations
_ Context _

Employee

salary

13000

Customer

loyalty_level

credit_limit

gold

10000

gold

20000

silver

5000

When a decision model is evaluated, its input data described by an item definition such as an XML Schema element (clause 7.3.2) is bound to case data mapped to the FEEL domain. The case data can be in various formats, such as XML. We can notate case data as an equivalent boxed context, as above. Decision logic can reference entries in the context using expressions such as Context.tns$Employee.tns$salary, which has a value of 13000.

Built-in functions

To promote interoperability, FEEL includes a library of built-in functions. The syntax and semantics of the built-ins are required for a conformant FEEL implementation.

In all of the tables in this section, a superscript refers to an additional domain constraint stated in the corresponding footnote to the table. Whenever a parameter is outside its domain, the result of the built-in is null.

Conversion functions

FEEL supports many conversions between values of different types. Of particular importance is the conversion from strings to dates, times, and durations. There is no literal representation for date, time, or duration. Also, formatted numbers such as 1,000.00 must be converted from a string by specifying the grouping separator and the decimal separator.

Built-ins are summarized in Table 72. The first column shows the name and parameters. A question mark (?) denotes an optional parameter. The second column specifies the domain for the parameters. The parameter domain is specified as one of:

a type, e.g., number, stringany – any element from the semantic domain, including nullnot null – any element from the semantic domain, excluding nulldate string – a string value in the lexical space of the date datatype specified by XML Schema Part 2 Datatypes time string – eithera string value in the lexical space of the time datatype specified by XML Schema Part 2 Datatypes; or
a string value that is the extended form of a local time representation as specified by ISO 8601, followed by the character "@", followed by a string value that is a time zone identifier in the IANA Time Zones Database (http://www.iana.org/time-zones)http://www.iana.org/time-zones)]

Table 44. [_Toc87279018 .anchor]#Table88: Conditional attributes and model associations
_ Name(parameters) _ _ Parameter Domain _ _ Description _ _ Example _

date(from)

date string

convert from to a date

date("2012-12-25") – date("2012-12-24") = duration("P1D ")

date(from)

date and time

convert from to a date (set time components to null)

date(
date and time("2012-12-25T1 1:00:00Z")) = date("2012-12-25")

date(year, month, day)

year, month, day are numbers

creates a date from year, month, day component values

date (2012, 12, 25) = date("2012-12-25")

date and time(date, time)

date is a date or date time; time is a time

creates a date time from the given date (ignoring any time component) and the given time

date and time ("2012-12-24T23:59:00") = date and time (date("2012-12-24”),
time (“23:59:00"))

date and time(from)

date time string

convert from to a date and time

date and time("2012-12-24T23:59:00") + duration("PT1M") = date and time("2012- 12-25T00:00:00")

time(from)

time string

convert from to time

time("23:59:00z") + duration("PT2M") = time("00:01:00@Etc/UTC")

time(from)

time, date and time

convert from to time (ignoring date components)

time(
date and time("2012-12-25T1 1:00:00Z")) = time("1 1:00:00Z")

time(hour, minute, second, offset?)

hour, minute, second, are numbers, offset is a days and time duration, or null

creates a time from the given component values

time (“23:59:00z") =
time (23, 59, 0, duration(“PT0H”))

number(from, grouping separator, decimal separator)

string1, string, string

convert from to a number

number("1 000,0", " ", ",") =
number("1,000.0", " ,", ".")

string(from)

non-null

convert from to a string

string(1.1) = "1.1" string(null) = null

duration(from)

duration string

convert from to a days and time or years and months duration

date and time("2012-12-24T23:59:00") - date and time("2012-12-22T03:45:00") = duration("P2DT20H14M")

duration("P2Y2M") = duration("P26M")

years and months duration(from, to)

both are date or both are date and time

return years and months duration between from and to

years and months duration (date("201 1-12-22"), date("2013-08-24") ) = duration("P1Y8M")

1. grouping SHALL be one of space (' '), comma (','), period ('.'), or null.
decimal SHALL be one of period, comma, or null, but SHALL NOT be the same as the grouping separator unless both are null.
from SHALL conform to grammar rule 37, after removing all occurrences of the grouping separator, if any, and after changing the decimal separator, if present, to a period.

Boolean function

Table 73 defines Boolean functions.

Table 45. [_Toc87279019 .anchor]#Table89: ChildExpression attributes and model associations
_ Name(parameters) _ _ Parameter Domain _ _ Description _ _ Example _

not(negand)

boolean

logical negation

not(true) = false not(null) = null

String functions

Table 74 defines string functions.

Table 46. [_Toc87279020 .anchor]#Table90: Filter attributes and model associations
_ Name(parameters) _ _ Parameter Domain _ _ Description _ _ Example _

substring(string, start position, length?)

string, number1

return length (or all) characters in string, starting at start position. 1st position is 1, last position is -1

substring("foobar",3) = "obar" substring("foobar",3,3) = "oba" substring("foobar", -2, 1) = "a"

substring("\U01F40Eab", 2) = "ab" where "\U01F40Eab" is the representation of 🐎ab

string length(string)

string

return number of characters (or code points) in string.

string length("foo") = 3
string length("\U01F40Eab") = 3

upper case(string)

string

return uppercased string

upper case("aBc4") = "ABC4"

lower case(string)

string

return lowercased string

lower case("aBc4") = "abc4"

substring before (string, match)

string, string

return substring of string before the match in string

Substring before("foobar","bar") = "foo" substring before("foobar","xyz") = ""

substring after
(string, match)

string, string

return substring of string after the match in string

substring after("foobar", "ob") = "ar" substring after("", "a") = ""

replace(input, pattern, replacement, flags?)

string2

regular expression pattern matching and replacement

replace("banana","a","o") = "bonono"

replace("abcd", _"(ab)

(a)", "[1=$1][2=$2]") = "[1=ab][2=]cd"_ __

contains(string, match)

string

does the string contain the match?

contains("foobar", "of") = false

starts with(string, match)

string

does the string start with the match?

starts with("foobar", "fo") = true

ends with( string, match)

string

does the string end with the match?

ends with("foobar", "r") = true

matches(input, pattern, flags?)

string2

does the input match the regexp pattern?

matches("foobar", "^fo*b") = true

split( string, delimiter )

string is a string, delimiter is a pattern2

Splits the string into a list of substrings, breaking at each occurrence of the delimiter pattern.

split( “John Doe”, “\\s” ) = [“John”, “Doe”] split( “a;b;c;;”, “;” ) = [“a”,”b”,”c”,””,””]

string join(list, delimiter)

list is a list of strings, delimiter is a string

return a string which is composed by joining all the string elements from the list parameter, separated by the delimiter.
The delimiter can be an empty string.
Null elements in the list parameter are ignored.
If list is empty, the result is the empty string.
If delimiter is null, the string elements are joined without a separator.

string join(["a","b","c"], "_and") = "a_and_b_and_c"_

string join(["a","b","c"], "") = "abc"

string join(["a","b","c"], null) = "abc"

string join(["a"], "X") = "a"

string join(["a",null,"c"], "X") = "aXc"

string join([], "X") = ""

string join(list)

list is a list of strings

return a string which is composed by joining all the string elements from the list parameter
Null elements in the list parameter are ignored.
If list is empty, the result is the empty string.

start position must be a non-zero integer (0 scale number) in the range [-L..L], where L is the length of the string. length must be in the range [1 ..E], where E is L – start position + 1 if start position is positive, and –start position otherwise.pattern, replacement, and flags SHALL conform to the syntax and constraints specified in clause 7.6 of XQuery 1.0 and XPath 2.0 Functions and Operators. Note that where XPath specifies an error result, FEEL specifies a null result.

List functions

Table 75 defines list functions.

Table 47. [_Toc87279021 .anchor]#Table91: Iterator attributes and model associations
_ Name(parameters) _ _ Parameter Domain _ _ Description _ _ Example _

list contains(list, element)

list, any element of the semantic domain including null

does the list contain the element?

list contains([1,2,3], 2) = true

count(list)

list

return size of list, or zero if list is empty

count([1,2,3]) = 3 count([]) = 0 count([1,[2,3]]) = 2

min(list)
min(c1,…​, cN), N >0 max(list)
max(c1,…​, cN), N >0

non-empy list of comparable items or argument list of one or more comparable items

return minimum(maximum) item, or null if list is empty

min([1,2,3]) = 1
max(1,2,3) = 3
min(1) = min([1]) = 1 max([]) = null

sum(list)
sum(n1,…​, nN), N >0

list of 0 or more numbers or argument list of one or more numbers

return sum of numbers, or null if list is empty

sum([1,2,3]) = 6 sum(1,2,3) = 6 sum(1) = 1
sum([]) = *null*

mean(list)
mean(n1,…​, nN), N >0

non-empty list of numbers or argument list of one or more numbers

return arithmetic mean (average) of numbers

mean ([1,2,3]) = 2 mean(1,2,3) = 2 mean(1) = 1 mean([]) = null

all(list)
all(b1,…​, bN), N >0

list of Boolean items or argument list of one or more Boolean items

return false if any item is false, else true if empty or all items are true, else null

all([false,null,true]) = false
all(true) = all([true]) = true
all([]) = true
all(0) = null

any(list)
any(b1,…​, bN), N >0

list of Boolean items or argument list of one or more Boolean items

return true if any item is true, else false if empty or all items are false, else null

any([false,null,true]) = true any(false) = false
any([]) = false
any(0) = null

sublist(list, start position, length?)

list, number1, number2

return list of length (or all) elements of list, starting with list[start position]. 1st position is 1, last position is -1

sublist([4,5,6], 1, 2) = [4,5]

append(list, item…​)

list, any element including null

return new list with items appended

append([1], 2, 3) = [1,2,3]

concatenate(list…​)

list

return new list that is a concatenation of the arguments

concatenate([1,2],[3]) = [1,2,3]

insert before(list, position, newItem)

list, number1, any element including null

return new list with newItem inserted at position

insert before ([1 ,3], 1,2) = [2,1,3]

remove(list, position)

list, number1

list with item at position removed

remove ([1 ,2,3], 2) = [1,3]

reverse(list)

list

reverse the list

reverse ([1 ,2,3]) = [3,2,1]

index of(list, match)

list, any element including null

return ascending list of list positions containing match

index of([1,2,3,2],2) = [2,4]

union(list…​)

list

concatenate with duplicate removal

union ([1,2],[2,3]) = [1,2,3]

distinct values(list)

list

duplicate removal

distinct values([1,2,3,2, 1]) = [1,2,3]

flatten(list)

list

flatten nested lists

flatten ([[1 ,2],[[3]], 4]) = [1,2,3,4]

product( list ) product( n1, …​, nn)

list is a list of numbers. n1 …​ nn are numbers.

Returns the product of the numbers

product([2, 3, 4]) = 24

product([]) = null

product(2, 3, 4) = 24

median( list ) median( n1, …​, nn )

list is a list of number. n1 …​ nn are numbers.

Returns the median element of the list of numbers. I.e., after sorting the list, if the list has an odd number of elements, it returns the middle element. If the list has an even number of elements, returns the average of the two middle elements. If the list is empty, returns null.

median( 8, 2, 5, 3, 4 ) = 4 median( [6, 1, 2, 3] ) = 2.5 median( [ ] ) = null

stddev( list ) stddev( n1, …​, nn )

list is a list of number. n1 …​ nn are numbers.

Returns the sample standard deviation of the list of numbers. If the list is empty or if the list contains only one element, the function returns null.

stddev( 2, 4, 7, 5 ) = 2.08166599946613273528229 7706979931
stddev( [ 47 ] ) = null
stddev( 47 ) = null

stddev( [ ] ) = null

mode( list ) mode( n1, …​, nn )

list is a list of number. n1 …​ nn are numbers.

Returns the mode of the list of numbers. If the result contains multiple elements, they are returned in ascending order. If the list is empty, an empty list is returned.

mode( 6, 3, 9, 6, 6 ) = [ 6 ] mode( [6, 1, 9, 6, 1] ) = [ 1, 6 ] mode( [ ] ) = [ ]

position must be a non-zero integer (0 scale number) in the range [-L..L], where L is the length of the listlength must be in the range [1 ..E], where E is L – start position + 1 if start position is positive, and –start position otherwise.

Numeric functions

Table 76 defines numeric functions.

Table 48. [_Toc87279022 .anchor]#Table92: For attributes and model associations
_ Name(parameters) _ _ Parameter Domain _ _ Description _ _ Example _

decimal(n, scale)

number, number1

return n with given scale

decimal(1/3, 2) = .33
decimal(1.5, 0) = 2
decimal(2. 5, 0) = 2

floor(n)

floor(n, scale)

number

number, number1

Return n with given scale and rounding mode flooring.

If at least one of n or scale is null the result is null.

For floor(n) the scale is 0

floor(1.5) = 1
floor(-1.56, 1) = -1.6

ceiling(n)

ceiling(n, scale)

number

number, number1

Return n with given scale and rounding mode ceiling.

If at least one of n or scale is null the result is null.

For ceiling(n) the scale is 0

ceiling(1.5) = 2
ceiling(-1.56, 1) = -1.5

round up(n, scale)

number, number1

Return n with given scale and rounding mode round up.

If at least one of n or scale is null the result is null.

round up(5.5, 0) = 6 _
round up(-5.5, 0) = -6_ _
round up(1.121, 2) = 1.13
round up(-1.126, 2) = -1.13_

round down(n, scale)

number, number1

Return n with given scale and rounding mode round down.

If at least one of n or scale is null the result is null.

round down(5.5, 0) = 5 _
round down (-5.5, 0) = -5_ _
round down (1.121, 2) = 1.12
round down (-1.126, 2) = -1.12_

round half up(n, scale)

number, number1

Return n with given scale and rounding mode round half up.

If at least one of n or scale is null the result is null.

round half up(5.5, 0) = 6 _
round half up(-5.5, 0) = -6_ _
round half up(1.121, 2) = 1.12
round half up(-1.126, 2) = -1.13_

round half down(n, scale)

number, number1

Return n with given scale and rounding mode round up.

If at least one of n or scale is null the result is null.

round half down (5.5, 0) = 5 _
round half down (-5.5, 0) = -5_ _
round half down (1.121, 2) = 1.12
round half down (-1.126, 2) = -1.13_

abs( n )

n is a number, a days and time duration or a year and month duration

Returns the absolute value of n.

abs( 10 ) = 10
abs( -10 ) = 10
abs(@”PT5H”) = @”PT5H”
abs(@”-PT5H”) = @”PT5H”

modulo( dividend, divisor )

dividend and divisor are numbers, where divisor must not be 0 (zero). Returns the remainder of the division of dividend by divisor. In case either dividend or divisor is negative, the result has the same sign of the divisor. The modulo function can be expressed as follows:

modulo (dividend, divisor) = dividend - divisor*floor (dividen d/divisor).

Returns the remainder of the division of dividend by divisor.

modulo( 12, 5 ) = 2
modulo(-12,5)= 3
modulo(12,-5)= -3
modulo(-12,-5)= -2 modulo(10. 1, 4.5)= 1.1 modulo(-10.1, 4.5)= 3.4 modulo(10.1, -4.5)= -3.4 modulo(-10.1, -4.5)= -1.1

sqrt( number )

number is a number.

Returns the square root of the given number. If number is negative it returns null.

sqrt( 16 ) = 4

log( number )

number is a number

Returns the natural logarithm (base e) of the number parameter.

log( 10 ) = 2.30258509299

exp( number )

number is a number

Returns the Euler’s number e raised to the power of number.

exp( 5 ) = 148.413159102577

odd( number )

number is a number

Returns true if number is odd, false if it is even.

odd( 5 ) = true
odd( 2 ) = false

even( number )

number is a number

Returns true if number is even, false if it is odd.

even( 5 ) = false
even ( 2 ) = true

1. Scale is in the range [−6111 ..6176]

Date and time functions

Table 77 defines date and time functions.

Table 49. [_Toc87279023 .anchor]#Table93: Quantified attributes and model associations
_ Name(parameters) _ _ Parameter Domain _ _ Description _ _ Example _

is(value1, value2)

Both are elements of the D

Returns true if both values are the same element in the FEEL semantic domain D (see 10.3.2.2)

is(date("2012-12-25"), time("23:00:50”)) is false

is(date("2012-12-25"), date("2012-12-25")) is true

is(time("23:00:50z"), time("23:00:50”)) is false

is(time("23:00:50z"), time("23:00:50+00:00”)) is true

Range Functions

The following set of functions establish relationships between single scalar values and ranges of such values. All functions in this list take two arguments and return True if the relationship between the argument holds, or False otherwise.

The specification of these functions is heavily inspired by the equivalent functions in the HL7 CQL (Clinical Quality Language) standard version 1.4.

The following table intuitively depicts the relationships defined by the functions in this chapter, but the full semantics of the functions are listed in

Table 78.

image

Table 50. [_Toc87279024 .anchor]#Table 94: DMNDI attributes
_ Name(parameters) _ _ Evaluates to true if and only if (for each signature, respectively) _ _ Example _

(a) before(point1, point2)

(a)
point1 < point2

before( 1, 10 ) = true
before( 10, 1 ) = false

(b) before(point, range)

(b)
point < range.start
or
(point = range.start
and
not(range.start included) )

before( 1, [1.. 10] ) = false
before( 1, (1..10] ) = true
before( 1, [5.. 10] ) = true

(c) before(range, point)

(c)
range.end < point
or
(range.end = point
and
not(range.end included) )

before( [1..10], 10 ) = false
before( [1..10), 10 ) = true
before( [1..10], 15 ) = true

(d) before(range1,range2)

(d)
range 1 .end < range2.start
or
not(range1 .end included) + or + not(range2.start included
and
range 1 .end = range2.start)

before( [1..10], [15..20] ) = true
before( [1..10], [10..20] ) = false
before( [1..10), [10..20] ) = true
before( [1..10], (10..20] ) = true

(a) after(point1, point2)

(a)
point1 > point2

after( 10, 5 ) = true
after( 5, 10 ) = false

(b) after(point, range)

(b)
point > range.end
or
(point = range.end
and
not(range.end included) )

after( 12, [1..10] ) = true
after( 10, [1..10) ) = true
after( 10, [1..10] ) = false

(c) after(range, point)

(c)
range.start > point
or
(range.start = point
and
not(range.start included) )

after( [11..20], 12 ) = false
after( [11 ..20], 10 ) = true
after( (11..20], 11 ) = true
after( [11 ..20], 11 ) = false

(d) after(range1, range2)

(d)
range 1 .start > range2.end
or
(( not(range1 .start included)
or
not(range2.end included) )
and
range 1 .start = range2.end)

after( [11..20], [1..10] ) = true
after( [1 ..1 0], [11 ..20] ) = false
after( [11 ..20], [1.. 11) ) = true
after( (11..20], [1..11] ) = true

(a) meets(range1, range2)

(a)

range1.end included

and

range2.start included

and

range 1 .end = range2.start

meets( [1..5], [5..10] ) = true meets( [1..5), [5..10] ) = false meets( [1..5], (5..10] ) = false meets( [1..5], [6..10] ) = false

(a) met by(range1, range2)

(a)

range1.start included

and

range2.end included

and

range 1 .start = range2.end

met by( [5..10], [1..5] ) = true met by( [5..10], [1..5) ) = false met by( (5..10], [1..5] ) = false met by( [6..10], [1..5] ) = false

(a) overlaps(range1, range2)

(a)

(range1.end > range2.start

or

(range1.end = range2.start

and

range1.end included

and

range2.start included))

and

(range1.start < range2.end

or

(range1.start = range2.end

and

range1.start included

and

range2.end included))

overlaps( [1..5], [3..8] ) = true overlaps( [3..8], [1 ..5] ) = true overlaps( [1 ..8], [3..5] ) = true overlaps( [3..5], [1 ..8] ) = true overlaps( [1 ..5], [6..8] ) = false overlaps( [6..8], [1 ..5] ) = false overlaps( [1 ..5], [5..8] ) = true overlaps( [1 ..5], (5..8] ) = false overlaps( [1 ..5), [5..8] ) = false overlaps( [1 ..5), (5. .8] ) = false overlaps( [5..8], [1 ..5] ) = true overlaps( (5..8], [1 ..5] ) = false overlaps( [5..8], [1 ..5) ) = false overlaps( (5..8], [1 ..5) ) = false

(a) overlaps before(range1, range2)

(a)

(range1.start < range2.start

or

(range1.start = range2.start

and

range1.start included

and

not(range2.start included)))

and

(range1.end > range2.start

or

(range1.end = range2.start

and

range1.end included

and

range2.start included))

and

(range1.end < range2.end

or

(range1.end = range2.end

and

(not(range1.end included)

or

range2.end included )))

overlaps before( [1 ..5], [3..8] ) = true overlaps before( [1 ..5], [6..8] ) = false overlaps before( [1 ..5], [5..8] ) = true overlaps before( [1 ..5], (5..8] ) = false overlaps before( [1 ..5), [5..8] ) = false overlaps before( [1 ..5), (1. .5] ) = true overlaps before( [1 ..5], (1 ..5] ) = true
overlaps before( [1 ..5), [1 ..5] ) = false
overlaps before( [1 ..5], [1 ..5] ) = false

(a) overlaps after(range1, range2)

(a)
(range2.start < range1.start
or
(range2.start = range1.start
and
range2.start included
and
not( range 1.start included)))
and
(range2.end > range 1.start
or
(range2.end = range 1.start
and
range2.end included
and
range 1.start included ))
and
(range2.end < range1.end
or
(range2.end = range1.end
and
(not(range2.end included)
or
range1.end included)))

overlaps after( [3..8], [1 ..5]) = true
overlaps after( [6..8], [1 ..5]) = false
overlaps after( [5..8], [1 ..5]) = true
overlaps after( (5..8], [1 ..5]) = false
overlaps after( [5..8], [1 ..5)) = false
overlaps after( (1 ..5], [1 ..5) ) = true
overlaps after( (1 ..5], [1 ..5] ) = true
overlaps after( [1 ..5], [1 ..5) ) = false
overlaps after( [1 ..5], [1 ..5] ) = false

(a) finishes(point, range)

(a)
range.end included
and
range.end = point

finishes( 10, [1..10] ) = true
finishes( 10, [1..10) ) = false

(b) finishes(range1, range2)

(b)
range1.end included = range2.end included
and
range1.end = range2.end
and
(range1.start > range2.start
or
(range1.start = range2.start
and
(not(range1.start included)
or
range2.start included)))

finishes( [5..10], [1..10] ) = true
finishes( [5..10), [1..10] ) = false
finishes( [5..10), [1..10) ) = true
finishes( [1..10], [1..10] ) = true
finishes( (1..10], [1..10] ) = true

(a) finished by(range, point)

(a)
range.end included
and
range.end = point

finished by( [1..10], 10 ) = true
finished by( [1..10), 10 ) = false

(b) finished by(range1, range2)

(b)
range1.end included = range2.end included
and
range1.end = range2.end
and
(range1.start < range2.start
or
(range1.start = range2.start
and
(range1.start included
or
not(range2.start included))))

finished by( [1..10], [5..10] ) = true
finished by( [1..10], [5..10) ) = false
finished by( [1..10), [5..10) ) = true
finished by( [1..10], [1..10] ) = true
finished by( [1..10], (1..10] ) = true

(a) includes(range, point)

(a)
(range.start < point and range.end > point)
or
(range.start = point and range.start included)
or
(range.end = point and range.end included)

includes( [1..10], 5 ) = true
includes( [1..10], 12 ) = false
includes( [1..10], 1 ) = true
includes( [1..10], 10 ) = true
includes( (1..10], 1 ) = false
includes( [1..10), 10 ) = false

(b) includes(range1, range2)

(b)
(range1.start < range2.start
or
(range1.start = range2.start
and
(range1.start included
or
not(range2.start included))))
and
(range1.end > range2.end
or
(range1.end = range2.end
and
(range1.end included
or
not(range2.end included))))

includes( [1..10], [4..6] ) = true
includes( [1..10], [1..5] ) = true
includes( (1..10], (1..5] ) = true
includes( [1..10], (1..10) ) = true
includes( [1..10), [5..10) ) = true
includes( [1..10], [1..10) ) = true
includes( [1..10], (1..10] ) = true
includes( [1..10], [1..10] ) = true

(a) during(point, range)

(a)
(range.start < point and range.end > point)
or
(range.start = point and range.start included)
or
(range.end = point and range.end included)

during( 5, [1..10] ) = true
during( 12, [1..10] ) = false
during( 1, [1..10] ) = true
during( 10, [1..10] ) = true
during( 1, (1..10] ) = false
during( 10, [1..10) ) = false

(b) during(range1, range2)

(b)
(range2.start < range1.start
or
(range2.start = range1.start
and
(range2.start included
or
not(range1.start included))))
and
(range2.end > range1.end
or
(range2.end = range1.end
and
(range2.end included
or
not(range1.end included))))

during( [4..6], [1..10] ) = true
during( [1..5], [1..10] ) = true
during( (1..5], (1..10] ) = true
during( (1..10), [1..10] ) = true
during( [5..10), [1..10) ) = true
during( [1..10), [1..10] ) = true
during( (1..10], [1..10] ) = true
during( [1..10], [1..10] ) = true

(a) starts(point, range)

(a)
range.start = point
and
range.start included

starts( 1, [1..10] ) = true
starts( 1, (1..10] ) = false
starts( 2, [1..10] ) = false

(b) starts(range1, range2)

(b)
range1.start = range2.start
and
range1.start included = range2.start included
and
(range1.end < range2.end
or
(range1.end = range2.end
and
(not(range1.end included)
or
range2.end included)))

starts( [1..5], [1..10] ) = true
starts( (1..5], (1..10] ) = true
starts( (1..5], [1..10] ) = false
starts( [1..5], (1..10] ) = false
starts( [1..10], [1..10] ) = true
starts( [1..10), [1..10] ) = true
starts( (1..10), (1..10) ) = true

(a) started by(range, point)

(a)
range.start = point
and
range.start included

started by( [1..10], 1 ) = true
started by( (1..10], 1 ) = false
started by( [1..10], 2 ) = false

(b) started by(range1, range2)

(b)
range1.start = range2.start
and
range1.start included = range2.start included
and
(range2.end < range1.end
or
(range2.end = range1.end
and
(not(range2.end included)
or
range1.end included)))

started by( [1..10], [1..5] ) = true
started by( (1..10], (1..5] ) = true
started by( [1..10], (1..5] ) = false
started by( (1..10], [1..5] ) = false
started by( [1..10], [1..10] ) = true
started by( [1..10], [1..10) ) = true
started by( (1..10), (1..10) ) = true

(a) coincides(point1, point2)

(a) point1 = point2

coincides( 5, 5 ) = true
coincides( 3, 4 ) = false

(b) coincides(range1, range2)

(b) range1.start = range2.start
and
range1.start included = range2.start included
and
range1.end = range2.end
and
range1.end included = range2.end included

coincides( [1..5], [1..5] ) = true
coincides( (1..5), [1..5] ) = false
coincides( [1..5], [2..6] ) = false

Temporal built-in functions

The following set of functions provide common support utilities when dealing with date or date and time values; listed in Table 1.

Table 51. [_Toc87279025 .anchor]#Table 95: DMNDiagram attributes
_ Name(parameters) _ _ Parameter Domain _ _ Description _ _ Example _

day of year( date )

date or

date and time

returns the Gregorian number of the day within the year

day of year( date(2019, 9, 17) ) = 260

day of week( date )

date or date and time

returns the day of the week according to the Gregorian calendar enumeration: “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”, “Sunday”

day of week( date(2019, 9, 17) ) = "Tuesday"

month of year( date )

date or date and time

returns the month of the year according to the Gregorian calendar enumeration: “January”, “February”, “March”, “April”, “May”, “June”, “July”, “August”, “September”, “October”, “November”, “December”

month of year( date(2019, 9, 17) ) = "September"

week of year( date )

date or date and time

returns the Gregorian number of the week within the year, accordingly to ISO 8601

week of year( date(2019, 9, 17) ) = 38
week of year( date(2003, 12, 29) ) = 1
week of year( date(2004, 1, 4) ) = 1
week of year( date(2005, 1, 1) ) = 53
week of year( date(2005, 1, 3) ) = 1
week of year( date(2005, 1, 9) ) = 1

Sort

Sort a list using an ordering function. For example,

sort(list: [3,1,4,5,2], precedes: function(x,y) x < y) = [1,2,3,4,5]

Table 52. [_Toc87279026 .anchor]#Table 96: DMNDiagramElement attributes
_ Parameter name (* means optional) _ _ Domain _

list

list of any element, be careful with nulls

precedes

boolean function of 2 arguments defined on every pair of list elements

Context function

Table 81 defines Context functions

Table 53. [_Toc87279027 .anchor]#Table 97: DMNShape attributes
_ Name(parameters) _ _ Parameter domain _ _ Description _ _ Example _

get value(m, key)

context, string

select the value of the entry named key from context m

get value (\{key1 : "value1"}, "key1 ") = "value1"
get value (\{key1 : "value 1"}, "unexistent-key") = null

get entries(m)

context

produces a list of key,value pairs from a context m

get entries(\{key1 : "value 1 ", key2 : "value2"}) = [ \{ key : "key1 ", value : "value 1" }, \{key : "key2", value :

"value2"} ]

context(entries)

entries is a list of contexts, each context item SHALL have two entries having keys: "key" and "value", respectively.

Returns a new context that includes all specified entries.

If a context item contains additional entries beyond the required "key" and "value" entries, the additional entries are ignored.

If a context item is missing the required "key" and "value" entries, the final result is null.

See also: get entries() built-in function.

context([\{key:"a", value:1}, \{key:"b", value:2}]) = \{a:1, b:2}

context([\{key:"a", value:1}, \{key:"b", value:2, something: "else"}]) = \{a:1, b:2}

context([\{key:"a", value:1}, \{key:"b"}]) = null

(a) context put(context, key, value)

(a)

context is a context,

key is a string,

value is Any type

(a) Returns a new context that includes the new entry, or overriding the existing value if an entry for the same key already exists in the supplied context parameter.

A new entry is added as the last entry of the new context. If overriding an existing entry, the order of the keys maintains the same order as in the original context.

context put(\{x:1}, "y", 2) = \{x:1, y:2}

context put(\{x:1, y:0}, "y", 2) = \{x:1, y:2}

context put(\{x:1, y:0, z:0}, "y", 2) = \{x:1, y:2, z:0}

context put(\{x:1}, ["y"], 2) = context put(\{x:1}, "y", 2) = \{x:1, y:2}

(b) context put(context, keys, value)

(b)

context is a context,

keys is a list of string,

value is Any type

(b) Returns the composite of nested invocations to context put() for each item in keys hierarchy in context.

If keys is a list of 1 element, this is equivalent to context put(context, key', value), where key' is the only element in the list keys.

If keys is a list of 2 or more elements, this is equivalent of calling context put(context, key', value'), with:
key' is the head element in the list keys,
value' is the result of invocation of context put(context', keys', value), where:
context' is the result of context.key',
keys' is the remainder of the list keys without the head element key'.

If keys is an empty list or null, the result is null.

context put(\{x:1, y: \{a: 0} }, ["y", "a"], 2)

= context put(\{x:1, y: \{a: 0} }, "y", context put(\{a: 0}, ["a"], 2))

= \{x:1, y: \{a: 2} }

context put(\{x:1, y: \{a: 0} }, [], 2) = null

context merge(contexts)

contexts is a list of contexts

Returns a new context that includes all entries from the given contexts; if some of the keys are equal, the entries are overriden.

The entries are overridden in the same order as specified by the supplied parameter, with new entries added as the last entry in the new context.

context merge([\{x:1}, \{y:2}]) = \{x:1, y:2}

context merge([\{x:1, y:0}, \{y:2}]) = \{x:1, y:2}

Miscellaneous functions

The following set of functions provide support utilities for several miscellaneous use-cases. For example, when a decision depends on the current date, like deciding the support SLA over the weekends, additional charges for weekend delivery, etc.

It is important to note that the functions in this section are intended to be side-effect-free, but they are not deterministic and not idempotent from the perspective of an external observer.

Vendors are encouraged to guide end-users in ensuring deterministic behavior of the DMN model during testing, for example, through specific configuration.

Users are encouraged to isolate decision logic that uses these functions in specific DRG elements, such as Decisions. This encapsulation enables them to be overridden with synthetic values that remain constant across executions of the DMN model’s test cases.

Table 54. [_Toc87279028 .anchor]#Table 98: DMNEdge attributes
Name(parameters) Parameter domain Description

now()

(none)

returns current date and time

today()

(none)

returns current date

Execution Semantics of Decision Services

FEEL gives execution semantics to decision services defined in decision models where FEEL is the expression language. A decision service is semantically equivalent to a FEEL function whose parameters are the decision service inputs, and whose logic is a context assembled from the decision service’s decisions and knowledge requirements.

Decision service implementations SHALL return a result as described above, and MAY return additional information such as intermediate results, log records, debugging information, error messages, rule annotations, etc. The format of any additional information is left unspecified.

Every FEEL expression in a decision model has execution semantics. LiteralExpression (FEEL text) semantics is defined in 10.3. Boxed expressions described in 10.2.2 can be mapped to FEEL text and thus also have execution semantics.

Recall that a DecisionService is defined by four lists: inputData, inputDecisions, outputDecisions, and encapsulatedDecisions. The lists are not independent and thus not all required to be specified, e.g., each required decision (direct and indirect) of the outputDecisions must be an encapsulatedDecision, an inputDecision, or required by an inputDecision. For simplicity in the following, we assume that all four lists are correctly and completely specified.

A DecisionService is given execution semantics by mapping it to a FEEL function F. Let S be a DecisionService with input data id1, id2, …​, input decisions di1, di2, …​, encapsulated decisions de1, de2, …​, and output decisions do1, do2, …​. Each input data idi has a qualified name nidi. Each decision di has a qualified name ndi and a decision logic expression ed. The decisions may have knowledge requirements. In particular the decisions may require BusinessKnowledgeModels bkm1, bkm2, …​ and DecisionServices s1, s2, …​. BusinessKnowledgeModels have qualified names nbkmi and encapsulatedLogic fbkmi. DecisionServices have qualified names nsi and equivalent logic fsi, where the equivalent logic is defined recursively, binding si to S.

The syntax for FEEL function F is funcion(nid1, nid2, …​, ndi1, ndi2, …​ ) C.result, where C is the context \{

ns1 : fs1, ns2 : fs2, …​,

nbkm1 : fbkm1, nbkm2 : fbkm2, …​,

nde1 : ede1, nde2 : ede2, …​,

result: \{ ndo1 : edo1, ndo2 : edo2, . ..}

such that si, bkmi, dei and doi are partially ordered by requirements (e.g., the context entry for a required decision comes before a decision that requires it).

The qualified name of an element named E (decision, input data, decision service, or BKM) that is defined in the same decision model as S is simply E. Otherwise, the qualified name is I.E, where I is the name of the import element that refers to the model where E is defined.

The execution semantics of S is FEEL(F): a function that when invoked with values from the FEEL semantic domain bound to the parameters representing input data and input decisions, returns:

In the case of a single output decision(s), the single decision’s output value.In the case of multiple output decisions, a context consisting of all the output decisions' output values.XML elements SHALL map to the FEEL semantic domain as specified in section 10.3.3. Otherwise, details of the syntax of input/output data values and mapping to/from FEEL are undefined.

Metamodel

image

[_Toc87278866 .anchor]#Figure 10‑27: Expression class diagram

The class Expression is extended to support the four new kinds of boxed expressions introduced by FEEL, namely: Context, FunctionDefinition, Relation and List.

Boxed expressions are Expressions that have a standard diagrammatic representation (see clauses 7.2.1 and 10.2.1). FEEL contexts, function definitions, relations and lists SHOULD be modeled as Context, FunctionDefinition, Relation and List elements, respectively, and represented as a boxed expression whenever possible; that is, when they are top-level expressions, since an instance of LiteralExpression cannot contain another Expression element.

Context metamodel

A Context is composed of any number of contextEntrys, which are instances of ContextEntry.

A Context element is represented diagrammatically as a boxed context (clause 10.2.1.4). A FEEL context (grammar rule 57 and clause 10.3.2.6) SHOULD be modeled as a Context element whenever possible.

Context inherits all the attributes and model associations from Expression. Table 83 presents the additional attributes and model associations of the Context element.

Table 55. [_Toc87279029 .anchor]#Table 99: DMNLabel attributes
_ Attribute _ _ Description _

contextEntry: ContextEntry [*]

This attributes lists the instances of ContextEntry that compose this Context.

ContextEntry metamodel

The class ContextEntry is used to model FEEL context entries when a context is modeled as a Context element. ContextEntry is a specialization of DMNElement, from which it inherits the optional id, description, and label attributes.

An instance of ContextEntry is composed of an optional variable, which is an InformationItem element whose name is the key in the context entry, and of a value, which is the instance of Expression that models the expression in the context entry.

Table 84 presents the attributes and model associations of the ContextEntry element.

Table 56. [_Toc87279030 .anchor]#Table 100: DMNStyle attributes
_ Attribute _ _ Description _

variable: InformationItem [0..1]

The instance of InformationItem that is contained in this ContextEntry, and whose name is the key in the modeled context entry

value: Expression

The instance of Expression that is the expression in this ContextEntry

FunctionDefinition metamodel

A FunctionDefinition has formalParameters and a body. A FunctionDefinition element is represented diagrammatically as a boxed function, as described in clause. A FEEL function definition (grammar rule 55 and clause 10.3.2.15) SHOULD be modeled as a FunctionDefinition element whenever possible.

FunctionDefinition inherits all the attributes and model associations from Expression. Table 85 presents the additional attributes and model associations of the Function Definition element.

Table 57. [_Toc87279031 .anchor]#Table 101: Depiction Resolution for Decision
_ Attribute _ _ Description _

FormalParameter: InformationItem [*]

This attributes lists the instances of InformationItem that are the parameters of this Context.

body: Expression [0..1]

The instance of Expression that is the body in this FunctionDefinition

kind: FunctionKind = FEEL \{ FEEL

Java

PMML } __

The kind attribute defines the type of the FunctionDefinition. The default value is FEEL. Supported values also include Java and PMML

List metamodel

A List is simply a list of element, which are instances of Expressions. A List element is represented diagrammatically as a boxed list, as described in clause 10.2.1.5. A FEEL list (grammar rule 54 and clause 10.3.2.15) SHOULD be modeled as a List element whenever possible.

List inherits all the attributes and model associations from Expression. Table 86 presents the additional attributes and model associations of the List element.

Table 58. [_Toc87279032 .anchor]#Table 102: Depiction Resolution for Business Knowledge Model
_ Attribute _ _ Description _

element: Expression [*]

This attributes lists the instances of Expression that are the elements in this List.

Relation metamodel

A Relation is convenient shorthand for a list of similar contexts. A Relation has a column instead of repeated ContextEntrys, and a List is used for every row, with one of the List’s expression for each column value.

Relation inherits all the attributes and model associations from Expression. Table 87 presents the additional attributes and model associations of the Relation element.

Table 59. [_Toc87279033 .anchor]#Table 103: Depiction Resolution for Input Data
_ Attribute _ _ Description _

row: List [*]

This attributes lists the instances of List that compose the rows of this Relation.

column: InformationItem [*]

This attributes lists the instances of InformationItem that define the columns in this Relation.

Conditional metamodel

A Conditional is a visual way to express an if statement.

Conditional inherits all the attributes and model associations from Expression. Table 88 presents the additional attributes and model associations of the Conditional element.

Table 60. [_Toc87279034 .anchor]#Table 104: Depiction Resolution for Knowledge Source
_ Attribute _ _ Description _
Table 61. [_Toc87279035 .anchor]#Table 105: Depiction Resolution of Artifacts
if: ChildExpression This attribute holds the expression that is evaluate by the conditional expression.

then: ChildExpression

This attribute holds the expression that will be evaluated when the condition in the if statement evaluates to true.

else: ChildExpression

This attribute holds the expression that will be evaluated when the condition in the if statement evaluates to false.

ChildExpression metamodel

A ChildExpression is used to hold an expression inside a node. Table 89 presents the attributes of a ChildExpression.

Table 62. [_Toc87279036 .anchor]#Table 106: Depiction Resolution of Decision Service
_ Attribute _ _ Description _

id: ID[0..1]

Optional identifier for this element. SHALL be unique within its containing Definitions element.

value: Expression

The instance of Expression that is the expression in this ChildExpression

Filter metamodel

A Filter is a visual way to express list filtering.

Filter inherits all the attributes and model associations from Expression. Table XX presents the additional attributes and model associations of the Filter element.

Table 63. [_Toc87279037 .anchor]#Table 107: Depiction Resolution of Information Requirement
_ Attribute _ _ Description _

in: ChildExpression

This attribute holds the expression that is evaluate as the collection to be filtered.

match: ChildExpression

This attribute holds the expression that is used to filter the collection.

Iterator metamodel

An Iterator is the abstract class for all boxed iteration.

Iterator inherits all the attributes and model associations from Expression. Table 91 presents the additional attributes and model associations of the Iterator element.

Table 64. [_Toc87279038 .anchor]#Table 108: Depiction Resolution of Knowledge Requirement
_ Attribute _ _ Description _

iteratorVariable: String

This attribute holds name of the iterator variable that will be populated at each iteration.

in: TypedChildExpression

This attribute holds the expression that is evaluated as the collection to be processed.

For metamodel

A For is a representation of a loop.

For inherits all the attributes and model associations from Iterator. Table 92 presents the additional attributes and model associations of the For element.

Table 65. [_Toc87279039 .anchor]#Table 109: Depiction Resolution of Authority Requirement
_ Attribute _ _ Description _

return: ChildExpression

This attribute holds the expression that is evaluated to create the new collection that will be returned.

Quantified metamodel

A Quantified is an abstraction of an expression that is evaluated on each item of a collection.

Quantified inherits all the attributes and model associations from Iterator. Table XX presents the additional attributes and model associations of Quantified.

Table 66. [_Toc87279040 .anchor]#Table 110: Depiction Resolution of Association
_ Attribute _ _ Description _

satisfies: ChildExpression

This attribute holds the expression that is evaluated to determine if the current item satisfies a condition.

Every metamodel

Every is an expression where all “satisfies” needs to be true for it to return true.

Every inherits all the attributes and model associations of Quantified.

Some metamodel

Some is an expression where at least one of the “satisfies” needs to be true for it to return true.

Some inherits all the attributes and model associations of Quantified.

Examples

A good way to get a quick overview of FEEL is by example.

FEEL expressions may reference other FEEL expressions by name. Named expressions are contained in a context. Expressions are evaluated in a scope, which is a list of contexts in which to resolve names. The result of the evaluation is an element in the FEEL semantic domain.

Context

Figure 10‑28 shows the boxed context used for the examples. Such a context could arise in several ways. It could be part of the decision logic for a single, complex decision. Or, it could be a context that is equivalent to part of a DRG as defined in clause 10.4, where applicant, requested product, and credit history are input data instances, monthly income and monthly outgoings are the results of other decisions linked through information requirements, and PMT is a business knowledge model.

Table 67. [_Toc87279041 .anchor]#Table 111: BPMN tasks relevant to DMN
_ applicant _ _ age _ 51

maritalStatus

"M"

existingCustomer

false

monthly

income

10000

repayments

2500

expenses

3000

requested product

product type

"STANDARD LOAN"

rate

0.25

term

36

amount

100000.00

monthly income

applicant.monthly.income

monthly outgoings

applicant.monthly.repayments, applicant.monthly.expenses

credit history

record date

event

weight

date("2008-03-12")

"home mortgage"

100

date("2011-04-01")

"foreclosure warning"

150

PMT

(rate, term, amount)

(amount rate/12) / (1 - (1 + rate/12)*-term)

[_Toc87278867 .anchor]#Figure 10‑28: Example context

Notice that there are 6 top-level context entries, represented by the six rows of the table. The value of the context entry named 'applicant' is itself a context, and the value of the context entry named 'monthly' is itself a context. The value of the context entry named 'monthly outgoings' is a list, the value of the context entry named 'credit history' is a relation, i.e. a list of two contexts, one context per row. The value of the context entry named 'PMT' is a function with parameters 'rate', 'term', and 'amount'.

The following examples use the above context. Each example has a pair of equivalent FEEL expressions separated by a horizontal line. Both expressions denote the same element in the semantic domain. The second expression, the ‘answer’, is a literal value.

Calculation

[.underline]#monthly income * 12
#120000

The context defines monthly income as applicant.monthly.income, which is also defined in the context as 10,000. Twelve times the monthly income is 120,000.

If, In

[.underline]#if applicant.maritalStatus in (“M”, “S”) then “valid” else “not valid”
#“valid”

The in test determines if the left-hand side expression satisfies the list of values or ranges on the right-hand side. If satisfied, the if expression returns the value of the then expression. Otherwise, the value of the else expression is returned.

Sum entries of a list

[.underline]#sum (monthly outgoings)
#5500

Monthly outgoings is computed in the context as the list [applicant.monthly.repayments, applicant.monthly.expenses], or [2500, 3000]. The square brackets are not required to be written in the boxed context.

Invocation of user-defined PMT function

The PMT function defined in the context computes the monthly payments for a given interest rate, number of months, and loan amount.

PMT (requested product . rate,
requested product . term,
[.underline]#requested product . amount)___
#3975.982590125552338278440100112431

A function is invoked textually using a parenthesized argument list after the function name. The arguments are defined in the context, and are 0.25, 36, and 100,000, respectively.

Sum weights of a recent credit history

sum (credit history[record date > date (“2011-01-01”)].weight
150__

This is a complex "one-liner" that will be useful to expand into constituent sub-expressions:

 built-in: sum

o path expression ending in .weight

 filter: [record date > date("2011-01-01 ")]

An expression in square brackets following a list expression filters the list. Credit history is defined in the context as a relation, that is, a list of similar contexts. Only the last item in the relation satisfies the filter. The first item is too old. The path expression ending in .weight selects the value of the weight entry from the context or list of contexts satisfied by the filter. The weight of the last item in the credit history is 150. This is the only item that satisfies the filter, so the sum is 150 as well.

Determine if credit history contain a bankruptcy event

[.underline]#Some ch in credit history satisfies ch.event = “bankruptcy”
#false

The some expression determines if at least one element in a list or relation satisfies a test. There are no bankruptcy events in the credit history in the context.