The check that an expression is in S-FEEL, the simple subset of FEEL (DMN 1.6, clause 9; D-49).
S-FEEL restricts the syntax. Within it the semantics are those of FEEL, which clause 9 states
to be equivalent, so an expression that passes is run as any other, and nothing here is a
runtime matter. Feel.parse/2 and Feel.prepare/2 call check/4 after the parser when the dialect
is :s_feel; the parser itself reads FEEL, since the grammar of S-FEEL has no construct that the
grammar of FEEL lacks.
An expression that is not in S-FEEL is a syntax error with the code :outside_s_feel, one
diagnostic for each construct, in source order.
What is accepted
For an expression (entry: :expression, grammar rule 3 of clause 9):
- literals: numbers (with no exponent), strings (with the escapes
\',\",\\,\n,\r,\tand\uwith four hex digits, but not\U),trueandfalse; - names and qualified names (
a,first name,applicant.age); date("..."),time("...")andduration("...")with one string literal, and no other call;- arithmetic negation and
+ - * / **; - the comparisons
= != < <= > >=; - the operands of those are expressions again, as the grammar has it.
For a list of unary tests (entry: :unary_tests, rule 12):
-, andnot(...)of a list of tests;- a test is a value,
<,<=,>or>=followed by a value, or an interval. A value is a literal (a number can have a sign), a qualified name, or one of the three date and time literals.= xand!= xas tests are not there: a value alone is the equality.
Not in S-FEEL: and, or, if, for, some, every, between, in, instance of, lists,
contexts, filters, paths on anything but a name, function definitions, other calls (not(x) and
abs(x) too), @"..." literals, intervals as values, generalized unary tests (? > 5), exponents,
\U escapes, and comments.
Two grammars
The grammar as printed has no parentheses for grouping and no null literal. The specification
notes (08, 2.7) take both for omissions, as a decision table tests for missing data all the time.
grammar: :practical (the default) accepts them. grammar: :literal follows the printed grammar
and reports them. Nothing else differs: a path is still names and dots, so a path on a group,
(a).b, is reported in both.
What is not checked
The types of S-FEEL, which have no date and time, list, context, range or function, and the
roles it is required in (the allowed values of an item definition, the input expressions and
entries and the output entries of a decision table, D-49). Those are about the model and not
about the text.
iex> {:ok, _ast} = Feel.parse("(1 + 2) * 3", dialect: :s_feel)
iex> {:error, error} = Feel.parse("if x then 1 else 2", dialect: :s_feel)
iex> {error.kind, error.code, error.span}
{:syntax, :outside_s_feel, {0, 18}}
iex> {:error, error} = Feel.parse("(1 + 2) * 3", dialect: :s_feel, s_feel_grammar: :literal)
iex> hd(error.diagnostics).details.construct
:grouping
Summary
Functions
Checks the tokens and the syntax tree of a parsed S-FEEL expression or list of unary tests.
Returns the grammar, or raises ArgumentError when it is not :practical or :literal.
Types
Functions
@spec check(String.t(), [Feel.Syntax.Token.t()], Feel.AST.t(), [{:grammar, grammar()}]) :: :ok | {:error, [Feel.Diagnostic.t(), ...]}
Checks the tokens and the syntax tree of a parsed S-FEEL expression or list of unary tests.
source and tokens are what the lexer read, ast what the parser made of them. Returns :ok,
or every construct that is not in S-FEEL as a list of diagnostics with the code :outside_s_feel,
ordered by position. Raises ArgumentError for an unknown option.
Options
:grammar-:practical(default) or:literal; see the module documentation.
Returns the grammar, or raises ArgumentError when it is not :practical or :literal.
iex> Feel.Syntax.SFeel.validate_grammar!(:literal)
:literal