Preserves Path schema
Preserves Path is a language for selecting and filtering portions of a Preserves value. It has an associated schema describing the various kinds of Path expressions as abstract syntax.
The schema source below is taken from path/path.prs in the Preserves source code repository.
Preserves Path expressions come in several flavours: selectors, steps (axes and filters), and predicates. Each is described below along with its abstract syntax definitions.
Selectors and Steps
Selectors are a sequence of steps, applied one after the other to the currently-selected value. Each step transforms an input into zero or more outputs. A step is an axis or a filter.
Selector = [Step ...] .
Step = Axis / Filter .
Axes: selecting portions of the input
Each axis step generally selects some sub-portion or -portions of the current document. An
axis may also have a secondary filtering effect: for example, label
only applies to Records,
and will yield an empty result set when applied to any other kind of input.
Axis =
/ <values> # yields the immediate subvalues of the input nonrecursively
/ <descendants> # recurses through all descendant subvalues of the input
/ <at @key any> # extracts a subvalue named by the given key, if any
/ <label> # extracts a Record's label, if any
/ <keys> # extracts all keys (for subvalues) of the input, nonrecursively
/ <length> # extracts the length/size of the input, if any
/ <annotations> # extracts all annotations attached to the input
/ <embedded> # moves into the representation of an embedded value, if any
/ <parse @module [symbol ...] @name symbol> # parses using Preserves Schema
/ <unparse @module [symbol ...] @name symbol> # unparses using Preserves Schema
.
The parse
and unparse
variants name Schema definitions,
to be resolved by the eventual surrounding context in which the expression will be executed. A
parse
axis parses the input using a Schema definition; if the parse succeeds, the axis moves
into the parse result. Similarly, unparse
expects an abstract parse result, transforming it
back into a concrete value according to the Schema definition.
Filters: rejecting inputs
Each filter step generally applies some test to the current document as a whole, either emitting it unchanged (with exceptions, detailed below) or emitting no outputs at all.
Filter =
/ <nop> # Always emit the input
/ <compare @op Comparison @literal any> # Emit iff the comparison holds
/ <regex @regex string> # Emit iff input is String and regex matches
/ <test @pred Predicate> # Apply complex predicate
/ <real> # Emit iff input is Double, or Integer
/ <int> # TRUNCATE and emit iff Double or Integer
/ <kind @kind ValueKind> # Emit iff input kind matches
.
Complex predicates
The complex predicates in a test
filter are built up from logical connectives over selectors.
A Selector
predicate evaluates to true whenever, applied to its input, it results in a
non-empty output set.
Predicate =
/ Selector
/ <not @pred Predicate>
/ <or @preds [Predicate ...]>
/ <and @preds [Predicate ...]>
.
Comparison against a literal
Each compare
filter includes a Comparison
and a literal value to compare the input against.
For example, <compare eq 3>
only produces an output if the input is equal (according to the
Preserves semantic model) to
3
.
Comparison = =eq / =ne / =lt / =ge / =gt / =le .
NB. For inequalities (lt
/ge
/gt
/le
), comparison between values of different kinds is
undefined in the current draft specification.
Filtering by value kind
Each kind
filter selects only values from one of the kinds of Preserves value:
ValueKind =
/ =Boolean / =Double / =SignedInteger / =String / =ByteString / =Symbol
/ =Record / =Sequence / =Set / =Dictionary
/ =Embedded
.