Feel.Analysis.Paths (feel v0.1.0)

Copy Markdown View Source

The type of e.name from the type of e (D-65).

select/3 is the static counterpart of Feel.Runtime.Path.select/2: it takes the union that is the type of the source and the key, and gives the union that the selection can be and whether the run can report an error for it. A test checks the two against each other on many values.

The union of the source is taken one alternative at a time, and the result is the union of what each gives:

The alternativeThe selectionAn error
context<..., key: T, ...>T, whatever T is: a context type lists entries that are there (D-23)never
an open context without the keyAny | Null (a context type allows more entries than it lists)maybe
a closed context without the keyNull: it has the entries it lists and no othersalways
list<E>list<S>, where S is the union of the selections from the alternatives of E, and Null for what has no such entrynever
a date, a time, ...the type of the property, with the range of its values (Table 67): month is number in [1..12]never, or always for a name the kind has not
range<E>E | Null for start and end, boolean for the flagsnever
NullNullalways
Any, a named typeAny | Nullmaybe
anything elseNullalways

A union with an alternative that errors and one that does not is a maybe; the analyzer warns only about always. A component of the other kind of duration (duration("P1Y").days) is an error, as the TCK flags it, though Table 67 says null; time offset and timezone of a value that has none are null and no error.

A context type of the specification is open (Feel.Type.Conformance), and a declared type is one. The type of a context literal, and of a constant, is closed ({:closed_context, entries}, D-65): it has the entries it lists and no others, so the selection of an entry it does not list is Null for sure.

Normalization retains nested exclusions. A path reader requests a positive upper approximation of each union it inspects: the source, list elements, and context entries traversed for descendants. An excluded context is therefore not mistaken for a value with no properties. This approximation is local to reading; selecting an entry returns its declared union, including exclusions, unchanged.

The descendant

descend/2 is the type of e...name (D-65). The result is a list, and what is in it is known as far as the source is: a closed context is walked as the run walks a value, so {a: {b: n}}...b is list<number | Null> and {a: 1}...b is list<Null> (the list of nothing, Table 43). An open context may have entries that its type does not list, nested as deep as it likes, so what is in the list is Any | Null. The contexts in a list are not looked into (Feel.Runtime.Path), so a type that is a list is not either. A source that is Null or not a context is an error.

The value property of a date and a time is a number. That of a date and time is number | Null and a maybe: it is null with an error for one with no zone, which the type does not tell (D-68).

iex> context = [{:context, %{"age" => [:number, :null]}}]
iex> Feel.Analysis.Paths.select(context, "age")
{:ok, [:number, :null], :never}
iex> {:ok, type, :never} = Feel.Analysis.Paths.select([:date], "month")
iex> Feel.Type.Union.format(type)
"number in [1..12]"
iex> Feel.Analysis.Paths.select([{:context, %{}}], "age")
{:ok, [:any, :null], :maybe}
iex> Feel.Analysis.Paths.select([{:closed_context, %{}}], "age")
{:ok, [:null], :always}

Summary

Types

Whether the run can report an error for the selection, for the values of the type.

Functions

The type of the descendants of key in a value of type source, and whether it can be an error.

The type of the selection of key from a value of type source, and whether it can be an error.

Types

errors()

@type errors() :: :never | :maybe | :always

Whether the run can report an error for the selection, for the values of the type.

Functions

descend(source, key)

@spec descend(Feel.Type.Union.t(), Feel.Name.t()) ::
  {:ok, Feel.Type.Union.t(), errors()}

The type of the descendants of key in a value of type source, and whether it can be an error.

iex> Feel.Analysis.Paths.descend([{:closed_context, %{"a" => [:number]}}], "b")
{:ok, [{:list, [:null]}], :never}
iex> {:ok, type, :never} = Feel.Analysis.Paths.descend([{:closed_context, %{"a" => [{:closed_context, %{"b" => [:number]}}]}}], "b")
iex> Feel.Type.Union.format(type)
"list<number>"
iex> Feel.Analysis.Paths.descend([{:context, %{"b" => [:number]}}], "b")
{:ok, [{:list, [:any, :null]}], :never}

select(source, key)

@spec select(Feel.Type.Union.t(), Feel.Name.t()) ::
  {:ok, Feel.Type.Union.t(), errors()}

The type of the selection of key from a value of type source, and whether it can be an error.