From 86d2f9f9978e78d2b64e08c2daafda3a08c5f139 Mon Sep 17 00:00:00 2001 From: Maxime LABELLE Date: Sat, 19 Feb 2022 14:48:57 +0100 Subject: [PATCH 1/2] Split grammar into its own file. --- docs/specification.rst | 108 +-------------------- documentation/grammar/jmespath-grammar.txt | 104 ++++++++++++++++++++ 2 files changed, 105 insertions(+), 107 deletions(-) create mode 100644 documentation/grammar/jmespath-grammar.txt diff --git a/docs/specification.rst b/docs/specification.rst index dc957e1..fe2c5b6 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -46,113 +46,7 @@ Grammar The grammar is specified using ABNF, as described in `RFC4234`_ -:: - - expression = sub-expression / index-expression / comparator-expression - expression =/ or-expression / identifier - expression =/ and-expression / not-expression / paren-expression - expression =/ "*" / multi-select-list / multi-select-hash / literal - expression =/ function-expression / pipe-expression / raw-string - expression =/ current-node - sub-expression = expression "." ( identifier / - multi-select-list / - multi-select-hash / - function-expression / - "*" ) - pipe-expression = expression "|" expression - or-expression = expression "||" expression - and-expression = expression "&&" expression - not-expression = "!" expression - paren-expression = "(" expression ")" - index-expression = expression bracket-specifier / bracket-specifier - multi-select-list = "[" ( expression *( "," expression ) ) "]" - multi-select-hash = "{" ( keyval-expr *( "," keyval-expr ) ) "}" - keyval-expr = identifier ":" expression - bracket-specifier = "[" (number / "*" / slice-expression) "]" / "[]" - bracket-specifier =/ "[?" expression "]" - comparator-expression = expression comparator expression - slice-expression = [number] ":" [number] [ ":" [number] ] - comparator = "<" / "<=" / "==" / ">=" / ">" / "!=" - function-expression = unquoted-string ( - no-args / - one-or-more-args ) - no-args = "(" ")" - one-or-more-args = "(" ( function-arg *( "," function-arg ) ) ")" - function-arg = expression / expression-type - current-node = "@" - expression-type = "&" expression - - raw-string = "'" *raw-string-char "'" - raw-string-char = (%x20-26 / %x28-5B / %x5D-10FFFF) / preserved-escape / - raw-string-escape - preserved-escape = escape (%x20-26 / %28-5B / %x5D-10FFFF) - raw-string-escape = escape ("'" / escape) - literal = "`" json-value "`" - unescaped-literal = %x20-21 / ; space ! - %x23-5B / ; # - [ - %x5D-5F / ; ] ^ _ - %x61-7A ; a-z - %x7C-10FFFF ; |}~ ... - escaped-literal = escaped-char / (escape %x60) - number = ["-"]1*digit - digit = %x30-39 - identifier = unquoted-string / quoted-string - unquoted-string = (%x41-5A / %x61-7A / %x5F) *( ; A-Za-z_ - %x30-39 / ; 0-9 - %x41-5A / ; A-Z - %x5F / ; _ - %x61-7A) ; a-z - quoted-string = quote 1*(unescaped-char / escaped-char) quote - unescaped-char = %x20-21 / %x23-5B / %x5D-10FFFF - escape = %x5C ; Back slash: \ - quote = %x22 ; Double quote: '"' - escaped-char = escape ( - %x22 / ; " quotation mark U+0022 - %x5C / ; \ reverse solidus U+005C - %x2F / ; / solidus U+002F - %x62 / ; b backspace U+0008 - %x66 / ; f form feed U+000C - %x6E / ; n line feed U+000A - %x72 / ; r carriage return U+000D - %x74 / ; t tab U+0009 - %x75 4HEXDIG ) ; uXXXX U+XXXX - - ; The ``json-value`` is any valid JSON value with the one exception that the - ; ``%x60`` character must be escaped. While it's encouraged that implementations - ; use any existing JSON parser for this grammar rule (after handling the escaped - ; literal characters), the grammar rule is shown below for completeness:: - - json-value = false / null / true / json-object / json-array / - json-number / json-quoted-string - false = %x66.61.6c.73.65 ; false - null = %x6e.75.6c.6c ; null - true = %x74.72.75.65 ; true - json-quoted-string = %x22 1*(unescaped-literal / escaped-literal) %x22 - begin-array = ws %x5B ws ; [ left square bracket - begin-object = ws %x7B ws ; { left curly bracket - end-array = ws %x5D ws ; ] right square bracket - end-object = ws %x7D ws ; } right curly bracket - name-separator = ws %x3A ws ; : colon - value-separator = ws %x2C ws ; , comma - ws = *(%x20 / ; Space - %x09 / ; Horizontal tab - %x0A / ; Line feed or New line - %x0D ; Carriage return - ) - json-object = begin-object [ member *( value-separator member ) ] end-object - member = quoted-string name-separator json-value - json-array = begin-array [ json-value *( value-separator json-value ) ] end-array - json-number = [ minus ] int [ frac ] [ exp ] - decimal-point = %x2E ; . - digit1-9 = %x31-39 ; 1-9 - e = %x65 / %x45 ; e E - exp = e [ minus / plus ] 1*DIGIT - frac = decimal-point 1*DIGIT - int = zero / ( digit1-9 *DIGIT ) - minus = %x2D ; - - plus = %x2B ; + - zero = %x30 ; 0 - +.. literalinclude:: grammar/jmespath-grammar.txt In addition to the grammar, there is the following token precedence that goes from weakest to tightest binding: diff --git a/documentation/grammar/jmespath-grammar.txt b/documentation/grammar/jmespath-grammar.txt new file mode 100644 index 0000000..3724c4f --- /dev/null +++ b/documentation/grammar/jmespath-grammar.txt @@ -0,0 +1,104 @@ +expression = sub-expression / index-expression / comparator-expression +expression =/ or-expression / identifier +expression =/ and-expression / not-expression / paren-expression +expression =/ "*" / multi-select-list / multi-select-hash / literal +expression =/ function-expression / pipe-expression / raw-string +expression =/ current-node +sub-expression = expression "." ( identifier / + multi-select-list / + multi-select-hash / + function-expression / + "*" ) +pipe-expression = expression "|" expression +or-expression = expression "||" expression +and-expression = expression "&&" expression +not-expression = "!" expression +paren-expression = "(" expression ")" +index-expression = expression bracket-specifier / bracket-specifier +multi-select-list = "[" ( expression *( "," expression ) ) "]" +multi-select-hash = "{" ( keyval-expr *( "," keyval-expr ) ) "}" +keyval-expr = identifier ":" expression +bracket-specifier = "[" (number / "*" / slice-expression) "]" / "[]" +bracket-specifier =/ "[?" expression "]" +comparator-expression = expression comparator expression +slice-expression = [number] ":" [number] [ ":" [number] ] +comparator = "<" / "<=" / "==" / ">=" / ">" / "!=" +function-expression = unquoted-string ( + no-args / + one-or-more-args ) +no-args = "(" ")" +one-or-more-args = "(" ( function-arg *( "," function-arg ) ) ")" +function-arg = expression / expression-type +current-node = "@" +expression-type = "&" expression + +raw-string = "'" *raw-string-char "'" +raw-string-char = (%x20-26 / %x28-5B / %x5D-10FFFF) / preserved-escape / + raw-string-escape +preserved-escape = escape (%x20-26 / %28-5B / %x5D-10FFFF) +raw-string-escape = escape ("'" / escape) +literal = "`" json-value "`" +unescaped-literal = %x20-21 / ; space ! + %x23-5B / ; # - [ + %x5D-5F / ; ] ^ _ + %x61-7A ; a-z + %x7C-10FFFF ; |}~ ... +escaped-literal = escaped-char / (escape %x60) +number = ["-"]1*digit +digit = %x30-39 +identifier = unquoted-string / quoted-string +unquoted-string = (%x41-5A / %x61-7A / %x5F) *( ; A-Za-z_ + %x30-39 / ; 0-9 + %x41-5A / ; A-Z + %x5F / ; _ + %x61-7A) ; a-z +quoted-string = quote 1*(unescaped-char / escaped-char) quote +unescaped-char = %x20-21 / %x23-5B / %x5D-10FFFF +escape = %x5C ; Back slash: \ +quote = %x22 ; Double quote: '"' +escaped-char = escape ( + %x22 / ; " quotation mark U+0022 + %x5C / ; \ reverse solidus U+005C + %x2F / ; / solidus U+002F + %x62 / ; b backspace U+0008 + %x66 / ; f form feed U+000C + %x6E / ; n line feed U+000A + %x72 / ; r carriage return U+000D + %x74 / ; t tab U+0009 + %x75 4HEXDIG ) ; uXXXX U+XXXX + +; The ``json-value`` is any valid JSON value with the one exception that the +; ``%x60`` character must be escaped. While it's encouraged that implementations +; use any existing JSON parser for this grammar rule (after handling the escaped +; literal characters), the grammar rule is shown below for completeness:: + +json-value = false / null / true / json-object / json-array / + json-number / json-quoted-string +false = %x66.61.6c.73.65 ; false +null = %x6e.75.6c.6c ; null +true = %x74.72.75.65 ; true +json-quoted-string = %x22 1*(unescaped-literal / escaped-literal) %x22 +begin-array = ws %x5B ws ; [ left square bracket +begin-object = ws %x7B ws ; { left curly bracket +end-array = ws %x5D ws ; ] right square bracket +end-object = ws %x7D ws ; } right curly bracket +name-separator = ws %x3A ws ; : colon +value-separator = ws %x2C ws ; , comma +ws = *(%x20 / ; Space + %x09 / ; Horizontal tab + %x0A / ; Line feed or New line + %x0D ; Carriage return + ) +json-object = begin-object [ member *( value-separator member ) ] end-object +member = quoted-string name-separator json-value +json-array = begin-array [ json-value *( value-separator json-value ) ] end-array +json-number = [ minus ] int [ frac ] [ exp ] +decimal-point = %x2E ; . +digit1-9 = %x31-39 ; 1-9 +e = %x65 / %x45 ; e E +exp = e [ minus / plus ] 1*DIGIT +frac = decimal-point 1*DIGIT +int = zero / ( digit1-9 *DIGIT ) +minus = %x2D ; - +plus = %x2B ; + +zero = %x30 ; 0 \ No newline at end of file From 508dbad7dc48564c9d8a41139211b43810b0c42d Mon Sep 17 00:00:00 2001 From: Maxime LABELLE Date: Sat, 19 Feb 2022 15:19:38 +0100 Subject: [PATCH 2/2] Moved built-in function specifications to their own file. Fixed missing `values` function. --- docs/specification.rst | 1120 ++--------------- documentation/grammar/functions/abs.inc | 87 ++ documentation/grammar/functions/avg.inc | 35 + documentation/grammar/functions/ceil.inc | 28 + documentation/grammar/functions/contains.inc | 58 + documentation/grammar/functions/ends-with.inc | 30 + documentation/grammar/functions/floor.inc | 26 + documentation/grammar/functions/join.inc | 34 + documentation/grammar/functions/keys.inc | 37 + documentation/grammar/functions/length.inc | 45 + documentation/grammar/functions/map.inc | 33 + documentation/grammar/functions/max-by.inc | 34 + documentation/grammar/functions/max.inc | 35 + documentation/grammar/functions/merge.inc | 32 + documentation/grammar/functions/min-by.inc | 67 + documentation/grammar/functions/min.inc | 34 + documentation/grammar/functions/reverse.inc | 32 + documentation/grammar/functions/sort-by.inc | 37 + documentation/grammar/functions/sort.inc | 45 + .../grammar/functions/starts-with.inc | 29 + documentation/grammar/functions/sum.inc | 33 + documentation/grammar/functions/to-array.inc | 33 + documentation/grammar/functions/to-number.inc | 21 + documentation/grammar/functions/to-string.inc | 27 + documentation/grammar/functions/type.inc | 56 + documentation/grammar/functions/values.inc | 47 + 26 files changed, 1060 insertions(+), 1035 deletions(-) create mode 100644 documentation/grammar/functions/abs.inc create mode 100644 documentation/grammar/functions/avg.inc create mode 100644 documentation/grammar/functions/ceil.inc create mode 100644 documentation/grammar/functions/contains.inc create mode 100644 documentation/grammar/functions/ends-with.inc create mode 100644 documentation/grammar/functions/floor.inc create mode 100644 documentation/grammar/functions/join.inc create mode 100644 documentation/grammar/functions/keys.inc create mode 100644 documentation/grammar/functions/length.inc create mode 100644 documentation/grammar/functions/map.inc create mode 100644 documentation/grammar/functions/max-by.inc create mode 100644 documentation/grammar/functions/max.inc create mode 100644 documentation/grammar/functions/merge.inc create mode 100644 documentation/grammar/functions/min-by.inc create mode 100644 documentation/grammar/functions/min.inc create mode 100644 documentation/grammar/functions/reverse.inc create mode 100644 documentation/grammar/functions/sort-by.inc create mode 100644 documentation/grammar/functions/sort.inc create mode 100644 documentation/grammar/functions/starts-with.inc create mode 100644 documentation/grammar/functions/sum.inc create mode 100644 documentation/grammar/functions/to-array.inc create mode 100644 documentation/grammar/functions/to-number.inc create mode 100644 documentation/grammar/functions/to-string.inc create mode 100644 documentation/grammar/functions/type.inc create mode 100644 documentation/grammar/functions/values.inc diff --git a/docs/specification.rst b/docs/specification.rst index fe2c5b6..d6a5976 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -46,6 +46,7 @@ Grammar The grammar is specified using ABNF, as described in `RFC4234`_ +.. _RFC4234: https://tools.ietf.org/html/rfc4234 .. literalinclude:: grammar/jmespath-grammar.txt In addition to the grammar, there is the following token precedence that goes @@ -728,7 +729,65 @@ Examples search(foo[?a==b], {"foo": [{"a": 1, "b": 2}, {"a": 2, "b": 2}]}) -> [{"a": 2, "b": 2}] -.. _RFC4234: https://tools.ietf.org/html/rfc4234 +Pipe Expressions +================ + +:: + + pipe-expression = expression "|" expression + +A pipe expression combines two expressions, separated by the ``|`` character. +It is similar to a ``sub-expression`` with two important distinctions: + +1. Any expression can be used on the right hand side. A ``sub-expression`` + restricts the type of expression that can be used on the right hand side. +2. A ``pipe-expression`` **stops projections on the left hand side for + propagating to the right hand side**. If the left expression creates a + projection, it does **not** apply to the right hand side. + +For example, given the following data:: + + {"foo": [{"bar": ["first1", "second1"]}, {"bar": ["first2", "second2"]}]} + +The expression ``foo[*].bar`` gives the result of:: + + [ + [ + "first1", + "second1" + ], + [ + "first2", + "second2" + ] + ] + +The first part of the expression, ``foo[*]``, creates a projection. At this +point, the remaining expression, ``bar`` is projected onto each element of the +list created from ``foo[*]``. If you project the ``[0]`` expression, you will +get the first element from each sub list. The expression ``foo[*].bar[0]`` +will return:: + + ["first1", "first2"] + +If you instead wanted *only* the first sub list, ``["first1", "second1"]``, you +can use a ``pipe-expression``:: + + foo[*].bar[0] -> ["first1", "first2"] + foo[*].bar | [0] -> ["first1", "second1"] + + +Examples +-------- + +:: + + search(foo | bar, {"foo": {"bar": "baz"}}) -> "baz" + search(foo[*].bar | [0], { + "foo": [{"bar": ["first1", "second1"]}, + {"bar": ["first2", "second2"]}]}) -> ["first1", "second1"] + search(foo | [0], {"foo": [0, 1, 2]}) -> [0] + .. _functions: @@ -905,1037 +964,28 @@ for brevity, but the same rules apply. points; they do not take normalization into account. -.. _func-abs: - -abs ---- - -:: - - number abs(number $value) - -Returns the absolute value of the provided argument. The signature indicates -that a number is returned, and that the input argument ``$value`` **must** -resolve to a number, otherwise a ``invalid-type`` error is triggered. - -Below is a worked example. Given:: - - {"foo": -1, "bar": "2"} - -Evaluating ``abs(foo)`` works as follows: - -1. Evaluate the input argument against the current data:: - - search(foo, {"foo": -1, "bar": "2"}) -> -1 - -2. Validate the type of the resolved argument. In this case - ``-1`` is of type ``number`` so it passes the type check. - -3. Call the function with the resolved argument:: - - abs(-1) -> 1 - -4. The value of ``1`` is the resolved value of the function expression - ``abs(foo)``. - - -Below is the same steps for evaluating ``abs(bar)``: - -1. Evaluate the input argument against the current data:: - - search(bar, {"foo": -1, "bar": "2"}) -> "2" - -2. Validate the type of the resolved argument. In this case - ``"2"`` is of type ``string`` so we immediately indicate that - an ``invalid-type`` error occurred. - - -As a final example, here is the steps for evaluating ``abs(to_number(bar))``: - -1. Evaluate the input argument against the current data:: - - search(to_number(bar), {"foo": -1, "bar": "2"}) - -2. In order to evaluate the above expression, we need to evaluate - ``to_number(bar)``:: - - search(bar, {"foo": -1, "bar": "2"}) -> "2" - # Validate "2" passes the type check for to_number, which it does. - to_number("2") -> 2 - - Note that `to_number`_ is defined below. - -3. Now we can evaluate the original expression:: - - search(to_number(bar), {"foo": -1, "bar": "2"}) -> 2 - -4. Call the function with the final resolved value:: - - abs(2) -> 2 - -5. The value of ``2`` is the resolved value of the function expression - ``abs(to_number(bar))``. - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``abs(1)`` - - 1 - * - ``abs(-1)`` - - 1 - * - ``abs(`abc`)`` - - ```` - - -.. _func-avg: - -avg ---- - -:: - - number avg(array[number] $elements) - -Returns the average of the elements in the provided array. - -An empty array will produce a return value of null. - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15, 20]`` - - ``avg(@)`` - - 15 - * - ``[10, false, 20]`` - - ``avg(@)`` - - ```` - * - ``[false]`` - - ``avg(@)`` - - ```` - * - ``false`` - - ``avg(@)`` - - ```` - - -.. _func-contains: - -contains --------- - -:: - - boolean contains(array|string $subject, any $search) - -Returns ``true`` if the given ``$subject`` contains the provided ``$search`` -string. - -If ``$subject`` is an array, this function returns true if one of the elements -in the array is equal to the provided ``$search`` value. - -If the provided ``$subject`` is a string, this function returns true if -the string contains the provided ``$search`` argument. - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - n/a - - ``contains(`foobar`, `foo`)`` - - ``true`` - * - n/a - - ``contains(`foobar`, `not`)`` - - ``false`` - * - n/a - - ``contains(`foobar`, `bar`)`` - - ``true`` - * - n/a - - ``contains(`false`, `bar`)`` - - ```` - * - n/a - - ``contains(`foobar`, 123)`` - - ``false`` - * - ``["a", "b"]`` - - ``contains(@, `a`)`` - - ``true`` - * - ``["a"]`` - - ``contains(@, `a`)`` - - ``true`` - * - ``["a"]`` - - ``contains(@, `b`)`` - - ``false`` - * - ``["foo", "bar"]`` - - ``contains(@, `foo`)`` - - ``true`` - * - ``["foo", "bar"]`` - - ``contains(@, `b`)`` - - ``false`` - - -.. _func-ceil: - -ceil ----- - -:: - - number ceil(number $value) - -Returns the next highest integer value by rounding up if necessary. - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``ceil(`1.001`)`` - - 2 - * - ``ceil(`1.9`)`` - - 2 - * - ``ceil(`1`)`` - - 1 - * - ``ceil(`abc`)`` - - ``null`` - - -.. _func-ends-with: - -ends_with ---------- - -:: - - boolean ends_with(string $subject, string $prefix) - -Returns ``true`` if the ``$subject`` ends with the ``$prefix``, otherwise this -function returns ``false``. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``foobarbaz`` - - ``ends_with(@, ``baz``)`` - - ``true`` - * - ``foobarbaz`` - - ``ends_with(@, ``foo``)`` - - ``false`` - * - ``foobarbaz`` - - ``ends_with(@, ``z``)`` - - ``true`` - - -.. _func-floor: - -floor ------ - -:: - - number floor(number $value) - -Returns the next lowest integer value by rounding down if necessary. - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``floor(`1.001`)`` - - 1 - * - ``floor(`1.9`)`` - - 1 - * - ``floor(`1`)`` - - 1 - - -.. _func-join: - -join ----- - -:: - - string join(string $glue, array[string] $stringsarray) - -Returns all of the elements from the provided ``$stringsarray`` array joined -together using the ``$glue`` argument as a separator between each. - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``["a", "b"]`` - - ``join(`, `, @)`` - - "a, b" - * - ``["a", "b"]`` - - ``join(````, @)`` - - "ab" - * - ``["a", false, "b"]`` - - ``join(`, `, @)`` - - ```` - * - ``[false]`` - - ``join(`, `, @)`` - - ```` - -.. _func-keys: - -keys ----- - -:: - - array keys(object $obj) - -Returns an array containing the keys of the provided object. -Note that because JSON hashes are inheritently unordered, the -keys associated with the provided object ``obj`` are inheritently -unordered. Implementations are not required to return keys in -any specific order. - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``{"foo": "baz", "bar": "bam"}`` - - ``keys(@)`` - - ``["foo", "bar"]`` - * - ``{}`` - - ``keys(@)`` - - ``[]`` - * - ``false`` - - ``keys(@)`` - - ```` - * - ``[b, a, c]`` - - ``keys(@)`` - - ```` - - -.. _func-length: - -length ------- - -:: - - number length(string|array|object $subject) - -Returns the length of the given argument using the following types rules: - -1. string: returns the number of code points in the string -2. array: returns the number of elements in the array -3. object: returns the number of key-value pairs in the object - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - n/a - - ``length(`abc`)`` - - 3 - * - "current" - - ``length(@)`` - - 7 - * - "current" - - ``length(not_there)`` - - ```` - * - ``["a", "b", "c"]`` - - ``length(@)`` - - 3 - * - ``[]`` - - ``length(@)`` - - 0 - * - ``{}`` - - ``length(@)`` - - 0 - * - ``{"foo": "bar", "baz": "bam"}`` - - ``length(@)`` - - 2 - -.. _func-map: - -map ---- - -:: - - array[any] map(expression->any->any expr, array[any] elements) - -Apply the ``expr`` to every element in the ``elements`` array -and return the array of results. An ``elements`` of length -N will produce a return array of length N. - -Unlike a projection, (``[*].bar``), ``map()`` will include -the result of applying the ``expr`` for every element in the -``elements`` array, even if the result if ``null``. - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``{"array": [{"foo": "a"}, {"foo": "b"}, {}, [], {"foo": "f"}]}`` - - ``map(&foo, array)`` - - ``["a", "b", null, null, "f"]`` - * - ``[[1, 2, 3, [4]], [5, 6, 7, [8, 9]]]`` - - ``map(&[], @)`` - - ``[[1, 2, 3, 4], [5, 6, 7, 8, 9]]`` - - -.. _func-max: - -max ---- - -:: - - number max(array[number]|array[string] $collection) - -Returns the highest found number in the provided array argument. - -An empty array will produce a return value of null. - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15]`` - - ``max(@)`` - - 15 - * - ``["a", "b"]`` - - ``max(@)`` - - "b" - * - ``["a", 2, "b"]`` - - ``max(@)`` - - ```` - * - ``[10, false, 20]`` - - ``max(@)`` - - ```` - - -.. _func-max-by: - -max_by ------- - -:: - - max_by(array elements, expression->number|expression->string expr) - -Return the maximum element in an array using the expression ``expr`` as the -comparison key. The entire maximum element is returned. -Below are several examples using the ``people`` array (defined above) as the -given input. - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``max_by(people, &age)`` - - ``{"age": 50, "age_str": "50", "bool": false, "name": "d"}`` - * - ``max_by(people, &age).age`` - - 50 - * - ``max_by(people, &to_number(age_str))`` - - ``{"age": 50, "age_str": "50", "bool": false, "name": "d"}`` - * - ``max_by(people, &age_str)`` - - - * - ``max_by(people, age)`` - - - - -.. _func-merge: - -merge ------ - -:: - - object merge([object *argument, [, object $...]]) - -Accepts 0 or more objects as arguments, and returns a single object -with subsequent objects merged. Each subsequent object's key/value -pairs are added to the preceding object. This function is used -to combine multiple objects into one. You can think of this as -the first object being the base object, and each subsequent argument -being overrides that are applied to the base object. - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``merge(`{"a": "b"}`, `{"c": "d"}`)`` - - ``{"a": "b", "c": "d"}`` - * - ``merge(`{"a": "b"}`, `{"a": "override"}`)`` - - ``{"a": "override"}`` - * - ``merge(`{"a": "x", "b": "y"}`, `{"b": "override", "c": "z"}`)`` - - ``{"a": "x", "b": "override", "c": "z"}`` - - -.. _func-min: - -min ---- - -:: - - number min(array[number]|array[string] $collection) - -Returns the lowest found number in the provided ``$collection`` argument. - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15]`` - - ``min(@)`` - - 10 - * - ``["a", "b"]`` - - ``min(@)`` - - "a" - * - ``["a", 2, "b"]`` - - ``min(@)`` - - ```` - * - ``[10, false, 20]`` - - ``min(@)`` - - ```` - - -.. _func-min-by: - -min_by ------- - -:: - - min_by(array elements, expression->number|expression->string expr) - -Return the minimum element in an array using the expression ``expr`` as the -comparison key. The entire maximum element is returned. -Below are several examples using the ``people`` array (defined above) as the -given input. - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``min_by(people, &age)`` - - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` - * - ``min_by(people, &age).age`` - - 10 - * - ``min_by(people, &to_number(age_str))`` - - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` - * - ``min_by(people, &age_str)`` - - ```` - * - ``min_by(people, age)`` - - ```` - - -.. _not_null: - -not_null --------- - -:: - - any not_null([any $argument [, any $...]]) - -Returns the first argument that does not resolve to ``null``. This function -accepts one or more arguments, and will evaluate them in order until a -non null argument is encounted. If all arguments values resolve to ``null``, -then a value of ``null`` is returned. - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``{"a": null, "b": null, "c": [], "d": "foo"}`` - - ``not_null(no_exist, a, b, c, d)`` - - [] - * - ``{"a": null, "b": null, "c": [], "d": "foo"}`` - - ``not_null(a, b, `null`, d, c)`` - - ``"foo"`` - * - ``{"a": null, "b": null, "c": [], "d": "foo"}`` - - ``not_null(a, b)`` - - ``null`` - - -.. _func-reverse: - -reverse -------- - -:: - - array reverse(string|array $argument) - -Reverses the order of the ``$argument``. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[0, 1, 2, 3, 4]`` - - ``reverse(@)`` - - ``[4, 3, 2, 1, 0]`` - * - ``[]`` - - ``reverse(@)`` - - ``[]`` - * - ``["a", "b", "c", 1, 2, 3]`` - - ``reverse(@)`` - - ``[3, 2, 1, "c", "b", "a"]`` - * - ``"abcd`` - - ``reverse(@)`` - - ``dcba`` - - -.. _func-sort: - -sort ----- - -:: - - array sort(array[number]|array[string] $list) - -This function accepts an array ``$list`` argument and returns the sorted -elements of the ``$list`` as an array. - -The array must be a list of strings or numbers. Sorting strings is based on -code points. Locale is not taken into account. - - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[b, a, c]`` - - ``sort(@)`` - - ``[a, b, c]`` - * - ``[1, a, c]`` - - ``sort(@)`` - - ``[1, a, c]`` - * - ``[false, [], null]`` - - ``sort(@)`` - - ``[[], null, false]`` - * - ``[[], {}, false]`` - - ``sort(@)`` - - ``[{}, [], false]`` - * - ``{"a": 1, "b": 2}`` - - ``sort(@)`` - - ``null`` - * - ``false`` - - ``sort(@)`` - - ``null`` - - -.. _func-sort-by: - -sort_by -------- - -:: - - sort_by(array elements, expression->number|expression->string expr) - -Sort an array using an expression ``expr`` as the sort key. For each element -in the array of ``elements``, the ``expr`` expression is applied and the -resulting value is used as the key used when sorting the ``elements``. - -If the result of evaluating the ``expr`` against the current array element -results in type other than a ``number`` or a ``string``, a type error will -occur. - -Below are several examples using the ``people`` array (defined above) as the -given input. ``sort_by`` follows the same sorting logic as the ``sort`` -function. - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``sort_by(people, &age)[].age`` - - ``[10, 20, 30, 40, 50]`` - * - ``sort_by(people, &age)[0]`` - - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` - * - ``sort_by(people, &to_number(age_str))[0]`` - - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` - - -.. _func-starts-with: - -starts_with ------------ - -:: - - boolean starts_with(string $subject, string $prefix) - -Returns ``true`` if the ``$subject`` starts with the ``$prefix``, otherwise -this function returns ``false``. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``foobarbaz`` - - ``starts_with(@, ``foo``)`` - - ``true`` - * - ``foobarbaz`` - - ``starts_with(@, ``baz``)`` - - ``false`` - * - ``foobarbaz`` - - ``starts_with(@, ``f``)`` - - ``true`` - - -.. _func-sum: - -sum ---- - -:: - - number sum(array[number] $collection) - -Returns the sum of the provided array argument. - -An empty array will produce a return value of 0. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15]`` - - ``sum(@)`` - - 25 - * - ``[10, false, 20]`` - - ``max(@)`` - - ```` - * - ``[10, false, 20]`` - - ``sum([].to_number(@))`` - - 30 - * - ``[]`` - - ``sum(@)`` - - 0 - - -.. _func-to-array: - -to_array ---------- - -:: - - array to_array(any $arg) - -* array - Returns the passed in value. -* number/string/object/boolean - Returns a one element array containing - the passed in argument. - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``to_array(`[1, 2]`)`` - - ``[1, 2]`` - * - ``to_array(`"string"`)`` - - ``["string"]`` - * - ``to_array(`0`)`` - - ``[0]`` - * - ``to_array(`true`)`` - - ``[true]`` - * - ``to_array(`{"foo": "bar"}`)`` - - ``[{"foo": "bar"}]`` - - -.. _func-to-string: - - -to_string ---------- - -:: - - string to_string(any $arg) - -* string - Returns the passed in value. -* number/array/object/boolean - The JSON encoded value of the object. The - JSON encoder should emit the encoded JSON value without adding any additional - new lines. - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``to_string(`2`)`` - - ``"2"`` - - -.. _func-to-number: - -to_number ---------- - -:: - - number to_number(any $arg) - -* string - Returns the parsed number. Any string that conforms to the - ``json-number`` production is supported. Note that the floating number - support will be implementation specific, but implementations should support - at least IEEE 754-2008 binary64 (double precision) numbers, as this is - generally available and widely used. -* number - Returns the passed in value. -* array - null -* object - null -* boolean - null -* null - null - - -.. _func-type: - -type ----- - -:: - - string type(array|object|string|number|boolean|null $subject) - -Returns the JavaScript type of the given ``$subject`` argument as a string -value. - -The return value MUST be one of the following: - -* number -* string -* boolean -* array -* object -* null - - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - "foo" - - ``type(@)`` - - "string" - * - ``true`` - - ``type(@)`` - - "boolean" - * - ``false`` - - ``type(@)`` - - "boolean" - * - ``null`` - - ``type(@)`` - - "null" - * - 123 - - ``type(@)`` - - number - * - 123.05 - - ``type(@)`` - - number - * - ``["abc"]`` - - ``type(@)`` - - "array" - * - ``{"abc": "123"}`` - - ``type(@)`` - - "object" - - -.. _func-values: - -values ------- - -:: - - array values(object $obj) - -Returns the values of the provided object. -Note that because JSON hashes are inheritently unordered, the -values associated with the provided object ``obj`` are inheritently -unordered. Implementations are not required to return values in -any specific order. For example, given the input:: - - {"a": "first", "b": "second", "c": "third"} - -The expression ``values(@)`` could have any of these return values: - -* ``["first", "second", "third"]`` -* ``["first", "third", "second"]`` -* ``["second", "first", "third"]`` -* ``["second", "third", "first"]`` -* ``["third", "first", "second"]`` -* ``["third", "second", "first"]`` - -If you would like a specific order, consider using the -``sort`` or ``sort_by`` functions. - -.. cssclass:: table - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``{"foo": "baz", "bar": "bam"}`` - - ``values(@)`` - - ``["baz", "bam"]`` - * - ``["a", "b"]`` - - ``values(@)`` - - ```` - * - ``false`` - - ``values(@)`` - - ```` - - -Pipe Expressions -================ - -:: - - pipe-expression = expression "|" expression - -A pipe expression combines two expressions, separated by the ``|`` character. -It is similar to a ``sub-expression`` with two important distinctions: - -1. Any expression can be used on the right hand side. A ``sub-expression`` - restricts the type of expression that can be used on the right hand side. -2. A ``pipe-expression`` **stops projections on the left hand side for - propagating to the right hand side**. If the left expression creates a - projection, it does **not** apply to the right hand side. - -For example, given the following data:: - - {"foo": [{"bar": ["first1", "second1"]}, {"bar": ["first2", "second2"]}]} - -The expression ``foo[*].bar`` gives the result of:: - - [ - [ - "first1", - "second1" - ], - [ - "first2", - "second2" - ] - ] - -The first part of the expression, ``foo[*]``, creates a projection. At this -point, the remaining expression, ``bar`` is projected onto each element of the -list created from ``foo[*]``. If you project the ``[0]`` expression, you will -get the first element from each sub list. The expression ``foo[*].bar[0]`` -will return:: - - ["first1", "first2"] - -If you instead wanted *only* the first sub list, ``["first1", "second1"]``, you -can use a ``pipe-expression``:: - - foo[*].bar[0] -> ["first1", "first2"] - foo[*].bar | [0] -> ["first1", "second1"] - - -Examples --------- - -:: - - search(foo | bar, {"foo": {"bar": "baz"}}) -> "baz" - search(foo[*].bar | [0], { - "foo": [{"bar": ["first1", "second1"]}, - {"bar": ["first2", "second2"]}]}) -> ["first1", "second1"] - search(foo | [0], {"foo": [0, 1, 2]}) -> [0] +.. include:: grammar/functions/abs.inc +.. include:: grammar/functions/avg.inc +.. include:: grammar/functions/contains.inc +.. include:: grammar/functions/ceil.inc +.. include:: grammar/functions/ends-with.inc +.. include:: grammar/functions/floor.inc +.. include:: grammar/functions/join.inc +.. include:: grammar/functions/keys.inc +.. include:: grammar/functions/length.inc +.. include:: grammar/functions/map.inc +.. include:: grammar/functions/max.inc +.. include:: grammar/functions/max-by.inc +.. include:: grammar/functions/merge.inc +.. include:: grammar/functions/min.inc +.. include:: grammar/functions/min-by.inc +.. include:: grammar/functions/reverse.inc +.. include:: grammar/functions/sort.inc +.. include:: grammar/functions/sort-by.inc +.. include:: grammar/functions/starts-with.inc +.. include:: grammar/functions/sum.inc +.. include:: grammar/functions/to-array.inc +.. include:: grammar/functions/to-string.inc +.. include:: grammar/functions/to-number.inc +.. include:: grammar/functions/type.inc +.. include:: grammar/functions/values.inc diff --git a/documentation/grammar/functions/abs.inc b/documentation/grammar/functions/abs.inc new file mode 100644 index 0000000..1952644 --- /dev/null +++ b/documentation/grammar/functions/abs.inc @@ -0,0 +1,87 @@ +.. _func-abs: + +abs +--- + +:: + + number abs(number $value) + +Returns the absolute value of the provided argument. The signature indicates +that a number is returned, and that the input argument ``$value`` **must** +resolve to a number, otherwise a ``invalid-type`` error is triggered. + +Below is a worked example. Given:: + + {"foo": -1, "bar": "2"} + +Evaluating ``abs(foo)`` works as follows: + +1. Evaluate the input argument against the current data:: + + search(foo, {"foo": -1, "bar": "2"}) -> -1 + +2. Validate the type of the resolved argument. In this case + ``-1`` is of type ``number`` so it passes the type check. + +3. Call the function with the resolved argument:: + + abs(-1) -> 1 + +4. The value of ``1`` is the resolved value of the function expression + ``abs(foo)``. + + +Below is the same steps for evaluating ``abs(bar)``: + +1. Evaluate the input argument against the current data:: + + search(bar, {"foo": -1, "bar": "2"}) -> "2" + +2. Validate the type of the resolved argument. In this case + ``"2"`` is of type ``string`` so we immediately indicate that + an ``invalid-type`` error occurred. + + +As a final example, here is the steps for evaluating ``abs(to_number(bar))``: + +1. Evaluate the input argument against the current data:: + + search(to_number(bar), {"foo": -1, "bar": "2"}) + +2. In order to evaluate the above expression, we need to evaluate + ``to_number(bar)``:: + + search(bar, {"foo": -1, "bar": "2"}) -> "2" + # Validate "2" passes the type check for to_number, which it does. + to_number("2") -> 2 + + Note that `to_number`_ is defined below. + +3. Now we can evaluate the original expression:: + + search(to_number(bar), {"foo": -1, "bar": "2"}) -> 2 + +4. Call the function with the final resolved value:: + + abs(2) -> 2 + +5. The value of ``2`` is the resolved value of the function expression + ``abs(to_number(bar))``. + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Expression + - Result + * - ``abs(1)`` + - ``1`` + * - ``abs(-1)`` + - ``1`` + * - ``abs(`abc`)`` + - ```` + + diff --git a/documentation/grammar/functions/avg.inc b/documentation/grammar/functions/avg.inc new file mode 100644 index 0000000..9db7ca5 --- /dev/null +++ b/documentation/grammar/functions/avg.inc @@ -0,0 +1,35 @@ +.. _func-avg: + +avg +--- + +:: + + number avg(array[number] $elements) + +Returns the average of the elements in the provided array. + +An empty array will produce a return value of null. + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``[10, 15, 20]`` + - ``avg(@)`` + - ``15`` + * - ``[10, false, 20]`` + - ``avg(@)`` + - ```` + * - ``[false]`` + - ``avg(@)`` + - ```` + * - ``false`` + - ``avg(@)`` + - ```` + + diff --git a/documentation/grammar/functions/ceil.inc b/documentation/grammar/functions/ceil.inc new file mode 100644 index 0000000..2e85daf --- /dev/null +++ b/documentation/grammar/functions/ceil.inc @@ -0,0 +1,28 @@ +.. _func-ceil: + +ceil +---- + +:: + + number ceil(number $value) + +Returns the next highest integer value by rounding up if necessary. + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Expression + - Result + * - ``ceil(`1.001`)`` + - ``2`` + * - ``ceil(`1.9`)`` + - ``2`` + * - ``ceil(`1`)`` + - ``1`` + * - ``ceil(`abc`)`` + - ``null`` + + diff --git a/documentation/grammar/functions/contains.inc b/documentation/grammar/functions/contains.inc new file mode 100644 index 0000000..996a882 --- /dev/null +++ b/documentation/grammar/functions/contains.inc @@ -0,0 +1,58 @@ +.. _func-contains: + +contains +-------- + +:: + + boolean contains(array|string $subject, any $search) + +Returns ``true`` if the given ``$subject`` contains the provided ``$search`` +string. + +If ``$subject`` is an array, this function returns true if one of the elements +in the array is equal to the provided ``$search`` value. + +If the provided ``$subject`` is a string, this function returns true if +the string contains the provided ``$search`` argument. + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - n/a + - ``contains(`foobar`, `foo`)`` + - ``true`` + * - n/a + - ``contains(`foobar`, `not`)`` + - ``false`` + * - n/a + - ``contains(`foobar`, `bar`)`` + - ``true`` + * - n/a + - ``contains(`false`, `bar`)`` + - ```` + * - n/a + - ``contains(`foobar`, 123)`` + - ``false`` + * - ``["a", "b"]`` + - ``contains(@, `a`)`` + - ``true`` + * - ``["a"]`` + - ``contains(@, `a`)`` + - ``true`` + * - ``["a"]`` + - ``contains(@, `b`)`` + - ``false`` + * - ``["foo", "bar"]`` + - ``contains(@, `foo`)`` + - ``true`` + * - ``["foo", "bar"]`` + - ``contains(@, `b`)`` + - ``false`` + + diff --git a/documentation/grammar/functions/ends-with.inc b/documentation/grammar/functions/ends-with.inc new file mode 100644 index 0000000..a720739 --- /dev/null +++ b/documentation/grammar/functions/ends-with.inc @@ -0,0 +1,30 @@ +.. _func-ends-with: + +ends_with +--------- + +:: + + boolean ends_with(string $subject, string $prefix) + +Returns ``true`` if the ``$subject`` ends with the ``$prefix``, otherwise this +function returns ``false``. + + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``foobarbaz`` + - ``ends_with(@, `baz`)`` + - ``true`` + * - ``foobarbaz`` + - ``ends_with(@, `foo`)`` + - ``false`` + * - ``foobarbaz`` + - ``ends_with(@, `z`)`` + - ``true`` + + diff --git a/documentation/grammar/functions/floor.inc b/documentation/grammar/functions/floor.inc new file mode 100644 index 0000000..d080004 --- /dev/null +++ b/documentation/grammar/functions/floor.inc @@ -0,0 +1,26 @@ +.. _func-floor: + +floor +----- + +:: + + number floor(number $value) + +Returns the next lowest integer value by rounding down if necessary. + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Expression + - Result + * - ``floor(`1.001`)`` + - ``1`` + * - ``floor(`1.9`)`` + - ``1`` + * - ``floor(`1`)`` + - ``1`` + + diff --git a/documentation/grammar/functions/join.inc b/documentation/grammar/functions/join.inc new file mode 100644 index 0000000..e709f0d --- /dev/null +++ b/documentation/grammar/functions/join.inc @@ -0,0 +1,34 @@ +.. _func-join: + +join +---- + +:: + + string join(string $glue, array[string] $stringsarray) + +Returns all of the elements from the provided ``$stringsarray`` array joined +together using the ``$glue`` argument as a separator between each. + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``["a", "b"]`` + - ``join(`, `, @)`` + - ``"a, b"`` + * - ``["a", "b"]`` + - :literal:`join(\`\`, @)` + - ``"ab"`` + * - ``["a", false, "b"]`` + - ``join(`, `, @)`` + - ```` + * - ``[false]`` + - ``join(`, `, @)`` + - ```` + diff --git a/documentation/grammar/functions/keys.inc b/documentation/grammar/functions/keys.inc new file mode 100644 index 0000000..0eeadbf --- /dev/null +++ b/documentation/grammar/functions/keys.inc @@ -0,0 +1,37 @@ +.. _func-keys: + +keys +---- + +:: + + array keys(object $obj) + +Returns an array containing the keys of the provided object. +Note that because JSON hashes are inheritently unordered, the +keys associated with the provided object ``obj`` are inheritently +unordered. Implementations are not required to return keys in +any specific order. + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``{"foo": "baz", "bar": "bam"}`` + - ``keys(@)`` + - ``["foo", "bar"]`` + * - ``{}`` + - ``keys(@)`` + - ``[]`` + * - ``false`` + - ``keys(@)`` + - ```` + * - ``[b, a, c]`` + - ``keys(@)`` + - ```` + + diff --git a/documentation/grammar/functions/length.inc b/documentation/grammar/functions/length.inc new file mode 100644 index 0000000..73c516b --- /dev/null +++ b/documentation/grammar/functions/length.inc @@ -0,0 +1,45 @@ +.. _func-length: + +length +------ + +:: + + number length(string|array|object $subject) + +Returns the length of the given argument using the following types rules: + +1. string: returns the number of code points in the string +2. array: returns the number of elements in the array +3. object: returns the number of key-value pairs in the object + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - n/a + - ``length(`abc`)`` + - ``3`` + * - "current" + - ``length(@)`` + - ``7`` + * - "current" + - ``length(not_there)`` + - ```` + * - ``["a", "b", "c"]`` + - ``length(@)`` + - ``3`` + * - ``[]`` + - ``length(@)`` + - ``0`` + * - ``{}`` + - ``length(@)`` + - ``0`` + * - ``{"foo": "bar", "baz": "bam"}`` + - ``length(@)`` + - ``2`` + diff --git a/documentation/grammar/functions/map.inc b/documentation/grammar/functions/map.inc new file mode 100644 index 0000000..a63d917 --- /dev/null +++ b/documentation/grammar/functions/map.inc @@ -0,0 +1,33 @@ +.. _func-map: + +map +--- + +:: + + array[any] map(expression->any->any expr, array[any] elements) + +Apply the ``expr`` to every element in the ``elements`` array +and return the array of results. An ``elements`` of length +N will produce a return array of length N. + +Unlike a projection, (``[*].bar``), ``map()`` will include +the result of applying the ``expr`` for every element in the +``elements`` array, even if the result if ``null``. + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``{"array": [{"foo": "a"}, {"foo": "b"}, {}, [], {"foo": "f"}]}`` + - ``map(&foo, array)`` + - ``["a", "b", null, null, "f"]`` + * - ``[[1, 2, 3, [4]], [5, 6, 7, [8, 9]]]`` + - ``map(&[], @)`` + - ``[[1, 2, 3, 4], [5, 6, 7, 8, 9]]`` + + diff --git a/documentation/grammar/functions/max-by.inc b/documentation/grammar/functions/max-by.inc new file mode 100644 index 0000000..6208006 --- /dev/null +++ b/documentation/grammar/functions/max-by.inc @@ -0,0 +1,34 @@ +.. _func-max-by: + +max_by +------ + +:: + + max_by(array elements, expression->number|expression->string expr) + +Return the maximum element in an array using the expression ``expr`` as the +comparison key. The entire maximum element is returned. +Below are several examples using the ``people`` array (defined above) as the +given input. + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Expression + - Result + * - ``max_by(people, &age)`` + - ``{"age": 50, "age_str": "50", "bool": false, "name": "d"}`` + * - ``max_by(people, &age).age`` + - ``50`` + * - ``max_by(people, &to_number(age_str))`` + - ``{"age": 50, "age_str": "50", "bool": false, "name": "d"}`` + * - ``max_by(people, &age_str)`` + - ```` + * - ``max_by(people, age)`` + - ```` + + diff --git a/documentation/grammar/functions/max.inc b/documentation/grammar/functions/max.inc new file mode 100644 index 0000000..c076d0f --- /dev/null +++ b/documentation/grammar/functions/max.inc @@ -0,0 +1,35 @@ +.. _func-max: + +max +--- + +:: + + number max(array[number]|array[string] $collection) + +Returns the highest found number in the provided array argument. + +An empty array will produce a return value of null. + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``[10, 15]`` + - ``max(@)`` + - ``15`` + * - ``["a", "b"]`` + - ``max(@)`` + - ``"b"`` + * - ``["a", 2, "b"]`` + - ``max(@)`` + - ```` + * - ``[10, false, 20]`` + - ``max(@)`` + - ```` + + diff --git a/documentation/grammar/functions/merge.inc b/documentation/grammar/functions/merge.inc new file mode 100644 index 0000000..0abdd8e --- /dev/null +++ b/documentation/grammar/functions/merge.inc @@ -0,0 +1,32 @@ +.. _func-merge: + +merge +----- + +:: + + object merge([object *argument, [, object $...]]) + +Accepts 0 or more objects as arguments, and returns a single object +with subsequent objects merged. Each subsequent object's key/value +pairs are added to the preceding object. This function is used +to combine multiple objects into one. You can think of this as +the first object being the base object, and each subsequent argument +being overrides that are applied to the base object. + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Expression + - Result + * - ``merge(`{"a": "b"}`, `{"c": "d"}`)`` + - ``{"a": "b", "c": "d"}`` + * - ``merge(`{"a": "b"}`, `{"a": "override"}`)`` + - ``{"a": "override"}`` + * - ``merge(`{"a": "x", "b": "y"}`, `{"b": "override", "c": "z"}`)`` + - ``{"a": "x", "b": "override", "c": "z"}`` + + diff --git a/documentation/grammar/functions/min-by.inc b/documentation/grammar/functions/min-by.inc new file mode 100644 index 0000000..94c1079 --- /dev/null +++ b/documentation/grammar/functions/min-by.inc @@ -0,0 +1,67 @@ +.. _func-min-by: + +min_by +------ + +:: + + min_by(array elements, expression->number|expression->string expr) + +Return the minimum element in an array using the expression ``expr`` as the +comparison key. The entire maximum element is returned. +Below are several examples using the ``people`` array (defined above) as the +given input. + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Expression + - Result + * - ``min_by(people, &age)`` + - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` + * - ``min_by(people, &age).age`` + - ``10`` + * - ``min_by(people, &to_number(age_str))`` + - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` + * - ``min_by(people, &age_str)`` + - ```` + * - ``min_by(people, age)`` + - ```` + + +.. _not_null: + +not_null +-------- + +:: + + any not_null([any $argument [, any $...]]) + +Returns the first argument that does not resolve to ``null``. This function +accepts one or more arguments, and will evaluate them in order until a +non null argument is encounted. If all arguments values resolve to ``null``, +then a value of ``null`` is returned. + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``{"a": null, "b": null, "c": [], "d": "foo"}`` + - ``not_null(no_exist, a, b, c, d)`` + - ``[]`` + * - ``{"a": null, "b": null, "c": [], "d": "foo"}`` + - ``not_null(a, b, `null`, d, c)`` + - ``"foo"`` + * - ``{"a": null, "b": null, "c": [], "d": "foo"}`` + - ``not_null(a, b)`` + - ``null`` + + diff --git a/documentation/grammar/functions/min.inc b/documentation/grammar/functions/min.inc new file mode 100644 index 0000000..3c9c48d --- /dev/null +++ b/documentation/grammar/functions/min.inc @@ -0,0 +1,34 @@ +.. _func-min: + +min +--- + +:: + + number min(array[number]|array[string] $collection) + +Returns the lowest found number in the provided ``$collection`` argument. + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``[10, 15]`` + - ``min(@)`` + - ``10`` + * - ``["a", "b"]`` + - ``min(@)`` + - ``"a"`` + * - ``["a", 2, "b"]`` + - ``min(@)`` + - ```` + * - ``[10, false, 20]`` + - ``min(@)`` + - ```` + + diff --git a/documentation/grammar/functions/reverse.inc b/documentation/grammar/functions/reverse.inc new file mode 100644 index 0000000..72ab5b3 --- /dev/null +++ b/documentation/grammar/functions/reverse.inc @@ -0,0 +1,32 @@ +.. _func-reverse: + +reverse +------- + +:: + + array reverse(string|array $argument) + +Reverses the order of the ``$argument``. + + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``[0, 1, 2, 3, 4]`` + - ``reverse(@)`` + - ``[4, 3, 2, 1, 0]`` + * - ``[]`` + - ``reverse(@)`` + - ``[]`` + * - ``["a", "b", "c", 1, 2, 3]`` + - ``reverse(@)`` + - ``[3, 2, 1, "c", "b", "a"]`` + * - ``"abcd`` + - ``reverse(@)`` + - ``dcba`` + + diff --git a/documentation/grammar/functions/sort-by.inc b/documentation/grammar/functions/sort-by.inc new file mode 100644 index 0000000..04528aa --- /dev/null +++ b/documentation/grammar/functions/sort-by.inc @@ -0,0 +1,37 @@ +.. _func-sort-by: + +sort_by +------- + +:: + + sort_by(array elements, expression->number|expression->string expr) + +Sort an array using an expression ``expr`` as the sort key. For each element +in the array of ``elements``, the ``expr`` expression is applied and the +resulting value is used as the key used when sorting the ``elements``. + +If the result of evaluating the ``expr`` against the current array element +results in type other than a ``number`` or a ``string``, a type error will +occur. + +Below are several examples using the ``people`` array (defined above) as the +given input. ``sort_by`` follows the same sorting logic as the ``sort`` +function. + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Expression + - Result + * - ``sort_by(people, &age)[].age`` + - ``[10, 20, 30, 40, 50]`` + * - ``sort_by(people, &age)[0]`` + - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` + * - ``sort_by(people, &to_number(age_str))[0]`` + - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` + + diff --git a/documentation/grammar/functions/sort.inc b/documentation/grammar/functions/sort.inc new file mode 100644 index 0000000..ea6d213 --- /dev/null +++ b/documentation/grammar/functions/sort.inc @@ -0,0 +1,45 @@ +.. _func-sort: + +sort +---- + +:: + + array sort(array[number]|array[string] $list) + +This function accepts an array ``$list`` argument and returns the sorted +elements of the ``$list`` as an array. + +The array must be a list of strings or numbers. Sorting strings is based on +code points. Locale is not taken into account. + + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``[b, a, c]`` + - ``sort(@)`` + - ``[a, b, c]`` + * - ``[1, a, c]`` + - ``sort(@)`` + - ``[1, a, c]`` + * - ``[false, [], null]`` + - ``sort(@)`` + - ``[[], null, false]`` + * - ``[[], {}, false]`` + - ``sort(@)`` + - ``[{}, [], false]`` + * - ``{"a": 1, "b": 2}`` + - ``sort(@)`` + - ``null`` + * - ``false`` + - ``sort(@)`` + - ``null`` + + diff --git a/documentation/grammar/functions/starts-with.inc b/documentation/grammar/functions/starts-with.inc new file mode 100644 index 0000000..baeb8cc --- /dev/null +++ b/documentation/grammar/functions/starts-with.inc @@ -0,0 +1,29 @@ +.. _func-starts-with: + +starts_with +----------- + +:: + + boolean starts_with(string $subject, string $prefix) + +Returns ``true`` if the ``$subject`` starts with the ``$prefix``, otherwise +this function returns ``false``. + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``foobarbaz`` + - ``starts_with(@, `foo`)`` + - ``true`` + * - ``foobarbaz`` + - ``starts_with(@, `baz`)`` + - ``false`` + * - ``foobarbaz`` + - ``starts_with(@, `f`)`` + - ``true`` + + diff --git a/documentation/grammar/functions/sum.inc b/documentation/grammar/functions/sum.inc new file mode 100644 index 0000000..2da166a --- /dev/null +++ b/documentation/grammar/functions/sum.inc @@ -0,0 +1,33 @@ +.. _func-sum: + +sum +--- + +:: + + number sum(array[number] $collection) + +Returns the sum of the provided array argument. + +An empty array will produce a return value of 0. + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``[10, 15]`` + - ``sum(@)`` + - ``25`` + * - ``[10, false, 20]`` + - ``max(@)`` + - ```` + * - ``[10, false, 20]`` + - ``sum([].to_number(@))`` + - ``30`` + * - ``[]`` + - ``sum(@)`` + - ``0`` + + diff --git a/documentation/grammar/functions/to-array.inc b/documentation/grammar/functions/to-array.inc new file mode 100644 index 0000000..f67dec9 --- /dev/null +++ b/documentation/grammar/functions/to-array.inc @@ -0,0 +1,33 @@ +.. _func-to-array: + +to_array +--------- + +:: + + array to_array(any $arg) + +* array - Returns the passed in value. +* number/string/object/boolean - Returns a one element array containing + the passed in argument. + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Expression + - Result + * - ``to_array(`[1, 2]`)`` + - ``[1, 2]`` + * - ``to_array(`"string"`)`` + - ``["string"]`` + * - ``to_array(`0`)`` + - ``[0]`` + * - ``to_array(`true`)`` + - ``[true]`` + * - ``to_array(`{"foo": "bar"}`)`` + - ``[{"foo": "bar"}]`` + + diff --git a/documentation/grammar/functions/to-number.inc b/documentation/grammar/functions/to-number.inc new file mode 100644 index 0000000..d5043d8 --- /dev/null +++ b/documentation/grammar/functions/to-number.inc @@ -0,0 +1,21 @@ +.. _func-to-number: + +to_number +--------- + +:: + + number to_number(any $arg) + +* string - Returns the parsed number. Any string that conforms to the + ``json-number`` production is supported. Note that the floating number + support will be implementation specific, but implementations should support + at least IEEE 754-2008 binary64 (double precision) numbers, as this is + generally available and widely used. +* number - Returns the passed in value. +* array - null +* object - null +* boolean - null +* null - null + + diff --git a/documentation/grammar/functions/to-string.inc b/documentation/grammar/functions/to-string.inc new file mode 100644 index 0000000..499ed47 --- /dev/null +++ b/documentation/grammar/functions/to-string.inc @@ -0,0 +1,27 @@ +.. _func-to-string: + + +to_string +--------- + +:: + + string to_string(any $arg) + +* string - Returns the passed in value. +* number/array/object/boolean - The JSON encoded value of the object. The + JSON encoder should emit the encoded JSON value without adding any additional + new lines. + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Expression + - Result + * - ``to_string(`2`)`` + - ``"2"`` + + diff --git a/documentation/grammar/functions/type.inc b/documentation/grammar/functions/type.inc new file mode 100644 index 0000000..48b8e13 --- /dev/null +++ b/documentation/grammar/functions/type.inc @@ -0,0 +1,56 @@ +.. _func-type: + +type +---- + +:: + + string type(array|object|string|number|boolean|null $subject) + +Returns the JavaScript type of the given ``$subject`` argument as a string +value. + +The return value MUST be one of the following: + +* number +* string +* boolean +* array +* object +* null + + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``"foo"`` + - ``type(@)`` + - ``"string"`` + * - ``true`` + - ``type(@)`` + - ``"boolean"`` + * - ``false`` + - ``type(@)`` + - ``"boolean"`` + * - ``null`` + - ``type(@)`` + - ``"null"`` + * - ``123`` + - ``type(@)`` + - ``number`` + * - ``123.05`` + - ``type(@)`` + - ``number`` + * - ``["abc"]`` + - ``type(@)`` + - ``"array"`` + * - ``{"abc": "123"}`` + - ``type(@)`` + - ``"object"`` + + diff --git a/documentation/grammar/functions/values.inc b/documentation/grammar/functions/values.inc new file mode 100644 index 0000000..50f7ce5 --- /dev/null +++ b/documentation/grammar/functions/values.inc @@ -0,0 +1,47 @@ +.. _func-values: + +values +------ + +:: + + array values(object $obj) + +Returns the values of the provided object. +Note that because JSON hashes are inheritently unordered, the +values associated with the provided object ``obj`` are inheritently +unordered. Implementations are not required to return values in +any specific order. For example, given the input:: + + {"a": "first", "b": "second", "c": "third"} + +The expression ``values(@)`` could have any of these return values: + +* ``["first", "second", "third"]`` +* ``["first", "third", "second"]`` +* ``["second", "first", "third"]`` +* ``["second", "third", "first"]`` +* ``["third", "first", "second"]`` +* ``["third", "second", "first"]`` + +If you would like a specific order, consider using the +``sort`` or ``sort_by`` functions. + +.. cssclass:: table + +.. list-table:: Examples + :header-rows: 1 + + * - Given + - Expression + - Result + * - ``{"foo": "baz", "bar": "bam"}`` + - ``values(@)`` + - ``["baz", "bam"]`` + * - ``["a", "b"]`` + - ``values(@)`` + - ```` + * - ``false`` + - ``values(@)`` + - ```` +