What it means for a value to satisfy unary tests (DMN 1.6, sections 7.3.2 and 10.3.2.10; notes 08 §4.6 and §4.8).
The analyzer lowers each test to an expression about the input ?: < 5 becomes
? < 5, [1..5] becomes ? >= 1 and ? <= 5, and a value such as "a" becomes
? = "a" (D-40). Two things are left for the run, and are here:
matches/3: a test that is an expression whose value is only known at run time. Its value decides what the test means: a list is a set of alternatives, a range is containment, a boolean that is made from?is the answer, and anything else is equality with the input.satisfied/2: the tests together. They are alternatives, so atruedecides and anullis neither true nor false; the result is satisfied only when it istrue, or fornot(...)only when it isfalse.
Neither function gives null. A test that gives null (a null input against < 5, or
a number against "a") is not satisfied, and a negated list of tests with such a result
is not satisfied either (U2 in the notes).
Summary
Functions
The three-valued OR of the values of some tests: a true decides, and anything that is not a false
leaves it open. It is what in gives for its tests (D-61), where satisfied/2 turns the open case
into false.
Returns whether the input matches the value of a test that is an expression.
Returns whether the value of the subject of in is a member of the value of one of its tests (D-61).
Returns whether unary tests are satisfied, given the value of each test.
Functions
The three-valued OR of the values of some tests: a true decides, and anything that is not a false
leaves it open. It is what in gives for its tests (D-61), where satisfied/2 turns the open case
into false.
iex> Feel.Runtime.UnaryTests.any([false, true, nil])
true
iex> Feel.Runtime.UnaryTests.any([false, nil])
nil
iex> Feel.Runtime.UnaryTests.any([false, false])
false
iex> Feel.Runtime.UnaryTests.any([])
false
@spec matches(Feel.Value.t(), Feel.Value.t(), boolean()) :: Feel.Runtime.Env.outcome()
Returns whether the input matches the value of a test that is an expression.
uses_input? says whether the expression refers to ?.
- An expression that uses
?and is a boolean (ornull) is the answer itself. - A list matches when the input equals one of its elements.
- A range matches when the input lies within it.
- Any other value matches when the input equals it: a
nulltoo, if the expression does not use?.
The value decides and the type of the expression never does (D-209): an expression of ? that is null is
null, which is not satisfied, as null < 5 is, and a null that does not come from ? (a name that is
null) is equal to a null input. The analysis lowers a test to ? = expression only where that is the same.
Examples
iex> Feel.Runtime.UnaryTests.matches(Decimal.new(2), true, true)
{:ok, true}
iex> Feel.Runtime.UnaryTests.matches(Decimal.new(2), [Decimal.new(1), Decimal.new(2)], false)
{:ok, true}
iex> range = %Feel.Value.Range{start: Decimal.new(1), end: Decimal.new(5), start_included: true, end_included: false}
iex> Feel.Runtime.UnaryTests.matches(Decimal.new(5), range, false)
{:ok, false}
iex> Feel.Runtime.UnaryTests.matches(nil, nil, false)
{:ok, true}
iex> Feel.Runtime.UnaryTests.matches(nil, nil, true)
{:ok, nil}
iex> Feel.Runtime.UnaryTests.matches(Decimal.new(2), "a", false) |> elem(0)
:error
@spec member(Feel.Value.t(), Feel.Value.t(), boolean()) :: Feel.Runtime.Env.outcome()
Returns whether the value of the subject of in is a member of the value of one of its tests (D-61).
It is matches/3, except for a list, which Table 56 reads as list contains: the subject is in it when
it equals an element, or lies within an element that is a range, and an element that it cannot be
compared with is not equal to it, where matches/3 makes that an error.
iex> list = [Decimal.new(1), "a", Decimal.new(3)]
iex> Feel.Runtime.UnaryTests.member(Decimal.new(3), list, false)
{:ok, true}
iex> Feel.Runtime.UnaryTests.member(Decimal.new(2), list, false)
{:ok, false}
iex> range = %Feel.Value.Range{start: Decimal.new(5), end: Decimal.new(9), start_included: true, end_included: true}
iex> Feel.Runtime.UnaryTests.member(Decimal.new(6), [Decimal.new(1), range], false)
{:ok, true}
iex> Feel.Runtime.UnaryTests.member(true, [false, Decimal.new(2)], false)
{:ok, false}A subject that is found at the front stops the search:
iex> list = [Decimal.new(1), "a", Decimal.new(3)]
iex> Feel.Runtime.UnaryTests.member(Decimal.new(1), list, false)
{:ok, true}
Returns whether unary tests are satisfied, given the value of each test.
kind is :any for -, :positive for a list of tests, and :negated for
not(...). Each value is true, false or null.
iex> Feel.Runtime.UnaryTests.satisfied(:positive, [false, true])
true
iex> Feel.Runtime.UnaryTests.satisfied(:positive, [false, nil])
false
iex> Feel.Runtime.UnaryTests.satisfied(:negated, [false, false])
true
iex> Feel.Runtime.UnaryTests.satisfied(:negated, [false, nil])
false
iex> Feel.Runtime.UnaryTests.satisfied(:any, [])
true