Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functions to accept arrays; update coercion rules #187

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Given:
Visit the [Playground](https://opensource.adobe.com/json-formula/dist/index.html)

# Documentation
Specification / Reference: [HTML](https://opensource.adobe.com/json-formula/doc/output/json-formula-specification-1.1.0.html) / [PDF](https://opensource.adobe.com/json-formula/doc/output/json-formula-specification-1.1.0.pdf)
Specification / Reference: [HTML](https://opensource.adobe.com/json-formula/doc/output/json-formula-specification-1.1.2.html) / [PDF](https://opensource.adobe.com/json-formula/doc/output/json-formula-specification-1.1.2.pdf)

[JavaScript API](./doc/output/JSDOCS.md)

Expand Down
38 changes: 28 additions & 10 deletions doc/spec.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ If the supplied data is not correct for the execution context, json-formula will
* Operands of the union operator (`~`) shall be coerced to an array
* The left-hand operand of ordering comparison operators (`>`, `>=`, `<`, `\<=`) must be a string or number. Any other type shall be coerced to a number.
* If the operands of an ordering comparison are different, they shall both be coerced to a number
* Parameters to functions shall be coerced to the expected type as long as the expected type is a single choice. If the function signature allows multiple types for a parameter e.g. either string or array, then coercion will not occur.
* Parameters to functions shall be coerced when there is just a single viable coercion available. For example, if a null value is provided to a function that accepts a number or string, then coercion shall not happen, since a null value can be coerced to both types. Conversely if a string is provided to a function that accepts a number or array of numbers, then the string shall be coerced to a number, since there is no supported coercion to convert it to an array of numbers.

The equality and inequality operators (`=`, `==`, `!=`, `<>`) do **not** perform type coercion. If operands are different types, the values are considered not equal.

Expand All @@ -91,7 +91,7 @@ In all cases except ordering comparison, if the coercion is not possible, a `Typ
eval([1,2,3] ~ 4, {}) -> [1,2,3,4]
eval(123 < "124", {}) -> true
eval("23" > 111, {}) -> false
eval(abs("-2"), {}) -> 2
eval(avg(["2", "3", "4"]), {}) -> 3
eval(1 == "1", {}) -> false
----

Expand Down Expand Up @@ -127,6 +127,8 @@ In all cases except ordering comparison, if the coercion is not possible, a `Typ
| null | boolean | false
|===

An array may be coerced to another type of array as long as there is a supported coercion for the array content. e.g. just as a string can be coerced to a number, an array of strings may be coerced to an array of numbers.

[discrete]
==== Examples

Expand All @@ -135,7 +137,7 @@ In all cases except ordering comparison, if the coercion is not possible, a `Typ
eval("\"$123.00\" + 1", {}) -> TypeError
eval("truth is " & `true`, {}) -> "truth is true"
eval(2 + `true`, {}) -> 3
eval(avg("20"), {}) -> 20
eval(avg(["20", "30"]), {}) -> 25
----

=== Date and Time Values
Expand Down Expand Up @@ -433,7 +435,7 @@ The numeric and concatenation operators (`+`, `-`, `{asterisk}`, `/`, `&`) have

* When both operands are arrays, a new array is returned where the elements are populated by applying the operator on each element of the left operand array with the corresponding element from the right operand array
* If both operands are arrays and they do not have the same size, the shorter array is padded with null values
* If one operand is an array and one is a scalar value, a new array is returned where the operator is applied with the scalar against each element in the array
* If one operand is an array and one is a scalar value, the scalar operand will be converted to an array by repeating the value to the same size array as the other operand

[source%unbreakable]
----
Expand Down Expand Up @@ -1194,27 +1196,43 @@ output.
return_type function_name2(type1|type2 $argname)
----

=== Function parameters

Functions support the set of standard json-formula <<Data Types, data types>>. If the resolved arguments cannot be coerced to
match the types specified in the signature, a `TypeError` error occurs.

As a shorthand, the type `any` is used to indicate that the function argument can be
of any of (`array|object|number|string|boolean|null`).
any of (`array|object|number|string|boolean|null`).

The expression type, (denoted by `&expression`), is used to specify an
expression that is not immediately evaluated. Instead, a reference to that
expression is provided to the function being called. The function can then apply the expression reference as needed. It is semantically similar
to an https://en.wikipedia.org/wiki/Anonymous_function[anonymous function]. See the <<_sortBy, sortBy()>> function for an example of the expression type.

The result of the `functionExpression` is the result returned by the
function call. If a `functionExpression` is evaluated for a function that
does not exist, a `FunctionError` error is raised.

Functions can either have a specific arity or be variadic with a minimum
Function parameters can either have a specific arity or be variadic with a minimum
number of arguments. If a `functionExpression` is encountered where the
arity does not match, or the minimum number of arguments for a variadic function
is not provided, or too many arguments are provided, then a
`FunctionError` error is raised.

The result of the `functionExpression` is the result returned by the
function call. If a `functionExpression` is evaluated for a function that
does not exist, a `FunctionError` error is raised.

Many functions that process scalar values also allow for the processing of arrays of values. For example, the `round()` function may be called to process a single value: `round(1.2345, 2)` or to process an array of values: `round([1.2345, 2.3456], 2)`. The first call will return a single value, the second call will return an array of values.
When processing arrays of values, and where there is more than one parameter, each parameter is converted to an array so that the function processes each value in the set of arrays. From our example above, the call to `round([1.2345, 2.3456], 2)` would be processed as if it were `round([1.2345, 2.3456], [2, 2])`, and the result would be the same as: `[round(1.2345, 2), round(2.3456, 2)]`.

The rules for the treatment of parameters with arrays of values:

When any parameter is an array then:

* All parameters will be treated as arrays
* Any scalar parameters will be converted to an array by repeating the scalar value to the length of the longest array
* All array parameters will be padded to the length of the longest array by adding null values
* The function will return an array which is the result of iterating over the elements of the arrays and applying the function logic on the values at the same index.

=== Function evaluation

Functions are evaluated in applicative order:
- Each argument must be an expression
- Each argument expression must be evaluated before evaluating the
Expand Down
Loading
Loading