===============================================================================

This work is provided under the terms of the CREATIVE COMMONS PUBLIC
LICENSE. This work is protected by copyright and/or other applicable
law. Any use of the work other than as authorized under this license
or copyright law is prohibited.

http://creativecommons.org/licenses/by-nc-sa/2.5/

© 2016 OX Software GmbH

@author Daniel Rentz <daniel.rentz@open-xchange.com>

===============================================================================


1 Overview
==========

The modules in this sub directory provide implementations of all unary and
binary operators, and all functions supported by the client-side formula
interpreter. The function implementations are divided by categories into
several code modules.

Each operator and function is defined by a descriptor object. The descriptors
will be inserted into a map, keyed by the native name of the operator or
function as used in document operations (may differ to the translated function
names as used in the English user interface).

Example descriptor for the function ABS that returns the absolute value of a
floating-point number (see below for details about all properties):

var MATH_FUNCTIONS = {
        ...

        ABS: {
            minParams: 1,
            maxParams: 1,
            type: 'val',
            signature: 'val:num',
            resolve: Math.abs
        },

        ...
    };


2 Properties
============

Each function descriptor object supports the following properties:


* {String} category (optional)

The identifier of a function category the function is associated to, used e.g.
to distribute the available functions in several lists in the user interface.
Can be a list of space-separated category identifiers to assign the function to
multiple categories.


* {String} supported (optional)

The identifiers of all file formats that support the operator or function, as
space-separated list of string tokens. If omitted, all known file formats will
support the respective operator or function.

Supported file formats are:

- 'ooxml':
    The Office Open XML format, written e.g. by Microsoft Excel.

- 'odf':
    The Open Document Format, written e.g. by various Open Office variants.

Example:
    EASTERSUNDAY: {
        supported: 'odf',
        ...
    }


* {Boolean} hidden (optional, default value: false)

Whether to hide the function in the user interface. Can be used for outdated
functions from old versions of Spreadsheet applications, that will still be
supported if appearing in a formula, but should not be offered to the user.


* {String} altNames (optional)

One or more alternative names for a function, separated by whitespace. Using
one of these function names in a formula will invoke the same function resolver
as it does for the original function name.


* {String} altNamesHidden (optional)

One or more alternative names for a function, separated by whitespace, that are
accepted by the formula engine, but will be hidden in the user interface. Using
one of these function names in a formula will invoke the same function resolver
as it does for the original function name.


* {Number} minParams (required)

Minimum number of parameters supported by the operator or function. Must be 1
or 2 for operators.


* {Number} maxParams (optional)

Maximum number of parameters supported by the operator or function. Must not be
less than 'minParams'. Must be 1 or 2 for operators. For functions, can be
omitted to specify that the function accepts the maximum number of function
parameters supported by the current file format (last parameters can be
repeated, see property 'repeatParams' for details).


* {Number} repeatParams (optional, default value: 1)

If the function accepts as many parameters as supported by the current file
format (property 'maxParams' has been omitted), this property specifies the
length of a single sequence of parameters that will be repeated after the
minimum number of supported parameters (see property 'minParams'). Default
value is 1 (the same parameter is repeated).

Example 1:

The function SUM expects at least one parameter, but accepts as many parameters
as are supported by the current file format:

    SUM: {
        minParams: 1,
        ...
    }

Example 2:

The function SUMIFS expects pairs of repeating parameters following the first
parameter. The first pair is mandatory, the following pairs are optional:

    SUMIFS: {
        minParams: 3,
        repeatParams: 2,
        ...
    }


* {String} type (required)

The native type of the return value of the operator or function.

The following return types are supported:

- 'val'
    A single value (number, string, Boolean value, error code, date, or complex
    number). May cause repeated invocation of the operator or function, if
    called in a matrix type context. Example: in the formula
    =MDETERM(ABS(A1:B2)), the 'val'-type function ABS will be called once for
    each cell in the range, because function MDETERM expects a matrix as
    parameter.

- 'mat':
    A matrix constant (an instance of the class Matrix), even if it has size
    1x1.

- 'ref':
    A single unresolved cell range address (instance of the class Range3D), or
    an array of unresolved cell range addresses (instance of the class
    Range3DArray). Error code literals will be accepted too.

- 'any':
    The operator or function can return values of any of the previous type. The
    outer context of the operator or function will cause the appropriate type
    conversion.


* {String} signature (optional)

The type signature of the operator or function, as space-separated list of
tokens specifying the expected data type of the respective operands. Can be
omitted for functions without parameters. Will be ignored for unimplemented
operators or functions (missing 'resolve' property, see below).

The following data types are supported:

- 'val':
    A single literal value of type number, string, or Boolean. The special
    value null represents an empty function parameter, e.g. in the formula
    =SUM(1,,2). If the parameter is a constant matrix, its top-left element
    will be used. If the parameter is a cell range reference (an array of
    unresolved cell range addresses) with a single element, it will be resolved
    to the content value of the cell related to the reference cell of the
    formula. If the resulting value is an error code, it will be thrown as
    exception value, without resolving the operator or function.

- 'val:num':
    Similar to type 'val', but converts the parameter to a floating-point
    number (see method FormulaContext.convertToNumber() for details). If this
    conversion fails, the operator or function will result in a #VALUE! error.

- 'val:int':
    Similar to type 'val:num', but converts the parameter to an integer by
    rounding down after conversion to a floating-point number (see method
    FormulaContext.convertToNumber() for details). Negative numbers will be
    rounded down too (NOT towards zero). If this conversion fails, the operator
    or function will result in a #VALUE! error.

- 'val:date':
    Similar to type 'val', but converts the parameter to a Date object (see
    method FormulaContext.convertToDate() for details). If this conversion
    fails, the operator or function will result in a #VALUE! error.

- 'val:str':
    Similar to type 'val', but converts the parameter to a string (see method
    FormulaContext.convertToString() for details). If this conversion fails,
    the operator or function will result in a #VALUE! error.

- 'val:bool':
    Similar to type 'val', but converts the parameter to a Boolean value (see
    method FormulaContext.convertToBoolean() for details). If this conversion
    fails, the operator or function will result in a #VALUE! error.

- 'val:comp':
    Similar to type 'val', but converts the parameter to a complex number (see
    method FormulaContext.convertToComplex() for details). If this conversion
    fails, the operator or function will result in a #NUM! error.

- 'val:any':
    Similar to type 'val', but accepts error codes, and passes them as value to
    the resolver function.

- 'mat':
    A two-dimensional matrix of literal values available in formulas (numbers,
    strings, boolean values), as instance of the class Matrix. If the matrix
    contains one or more error codes, the first will be thrown as exception
    value, without resolving the operator or function. The maximum size of a
    constant matrix is restricted. Too large matrixes will cause to throw an
    UNSUPPORTED_ERROR error code. If the parameter is a single literal value,
    it will be converted to a 1x1 matrix (except for an error code which will
    be thrown). If the parameter is a cell range reference (an array of
    unresolved cell range addresses) with a single element, it will be resolved
    to a matrix with the content values of all cells in the range (unless the
    matrix would be too large, or one of the cells contains an error code).

- 'mat:num':
    Similar to type 'mat', but checks that all matrix elements are valid
    floating-point numbers. In difference to parameters of type 'val', other
    data types will NOT be converted to numbers, but result in throwing the
    #VALUE! error code immediately.

- 'mat:str':
    Similar to type 'mat', but checks that all matrix elements are strings. In
    difference to parameters of type 'val', other data types will NOT be
    converted to strings, but result in throwing the #VALUE! error code
    immediately.

- 'mat:bool':
    Similar to type 'mat', but checks that all matrix elements are boolean
    values. In difference to parameters of type 'val', other data types will
    NOT be converted to Boolean values, but result in throwing the #VALUE!
    error code immediately.

- 'mat:any':
    Similar to type 'mat', but accepts error codes as matrix elements, and
    passes them to the resolver function.

- 'ref':
    An array of unresolved cell range addresses, as instance of the class
    Range3DArray. If the actual parameter is not such an array, a special error
    code will be thrown indicating that the structure of the formula is
    considered invalid. If the parameter is an empty array, the #NULL! error
    code will be thrown instead.

- 'ref:sheet':
    Similar to type 'ref', but checks that all cell range addresses in the
    array refer to the same single sheet. If the parameter is an empty array,
    the #NULL! error code will be thrown instead. If the array contains ranges
    referring to different sheets, the #VALUE! error code will be thrown
    instead.

- 'ref:single':
    Similar to type 'ref', but tries to convert the range array to a single
    cell range address that refers to a single sheet (instance of the class
    Range3D). If the parameter is an empty array, the #NULL! error code will be
    thrown instead. If the array contains multiple ranges, or if the only range
    in the array refers to multiple sheets, the #VALUE! error code will be
    thrown instead.

- 'ref:multi':
    Similar to type 'ref:single', but accepts an array with one cell range
    address that refers to multiple sheets, and passes that single cell range
    address to the resolver function.

- 'any':
    The original operand (instance of class Operand): single value literals
    (including error codes), constant matrixes, or an unresolved cell range
    reference.


* {Function} resolve (optional)

The actual implementation of the operator or function. If omitted, the operator
or function will result in an 'unsupported' exception.

- Calling context:
    The resolver function will be called with an instance of the class
    FormulaContext as calling context. Thus, the symbol 'this' provides useful
    helper methods that can be used in the implementation of the operator or
    function.

(2) Parameters:
    The resolver function receives the converted operands according to the type
    signature specified in the property 'signature'. If the operands cannot be
    resolved to the specified types, the operator or function will result in
    the respective error code according to the error, or a fatal exception will
    be thrown specifying that the formula structure is invalid. The resolver
    function will not be invoked in this case.

(3) Return value:
    The resolver function must return either a literal value (number, string,
    boolean value, UTC Date object, complex number as instance of the class
    Complex, or an error code as instance of the class ErrorCode), a constant
    matrix (instance of the class Matrix) containing values of any of the types
    mentioned before, a single cell range address (instance of the class
    Range3D), an array of cell range addresses (instance of the class
    Range3DArray), or an unresolved operand as received by an 'any' parameter.
    If the returned number is infinite or NaN, it will be converted to a #NUM!
    error. If the returned (absolute) number is less than the least supported
    normalized positive number (see constant FormulaUtils.MIN_NUMBER), it will
    be converted to zero. All these rules apply to all numbers in a matrix too.

(4) Exceptions:
    Error code literals can be thrown as exception value, instead of being
    returned. This may happen implicitly, e.g. when using the data type
    conversion methods provided by the calling context (see class
    FormulaContext). Additionally, the resolver function may throw specific
    exception codes:

    - 'fatal':
        An unrecoverable internal error occurred. Interpretation of the formula
        will be canceled.


3 File Format Differences
=========================

Every property mentioned above but the property 'supported' can be an object
mapping different settings per file format. See description of the property
'supported' for a list of supported file formats.

Example 1:

The function CEILING has an optional second and third parameter in ODF, but is
fixed to 2 parameters in OOXML:

    CEILING: {
        minParams: { ooxml: 2, odf: 1 },
        maxParams: { ooxml: 2, odf: 3 },
        ...
    }

Example 2:

The power operator works differently in OOXML (where 0^0 results in #NUM!) and
ODF (where 0^0 results in 1):

    '^': {
        minParams: 2,
        maxParams: 2,
        ...
        resolve: { ooxml: FormulaUtils.power, odf: Math.pow }
    }
