OpenCReports expressions can use several operators and functions. The operator precedence is mostly as expected from the C programming language. One notable exception is implicit multiplication. The precedence classes are as below, in increasing order of precedence.
Note that all of the operators are implemented internally as a function call to the equivalent function. Since every function may be overridden by user functions, the operators may work differently than the documentation.
The ternary operator works as in the C, PHP and other languages:
expression1 ? expression2 : expression3
It's evaluated as follows: if the value of numeric
expression1
is true
(i.e. non-zero), then the result is the expression2
,
otherwise it's expression3
.
Type of expression2
and
expression3
may differ, i.e. the
result type will be the type of the underlying expression
but it can result in runtime errors.
Internally, it's implemented using the iif() function.
Logic OR can be written as ||
or
or
. Example: a || b
Logic AND can be written as &&
or
and
. Logic AND has precedence over OR.
Example: a && b
Internally, they are implemented using the Boolean AND and Boolean OR functions.
The bitwise operators in this precedence class and in their
increasing order of precedence are:
bitwise OR (|
) and
bitwise AND (&
).
The equality comparison operator can be written as
=
or ==
.
The inequality comparison operator can be written as
<>
or !=
.
Vector equality and inequality comparisons
have the same precedence as scalar comparisons.
These are not vectors in the mathematical sense,
but a comma separated list of scalars inside
brackets ([ ... ]
), with
op
being any of the
equality or inequality comparison operators:
[ expa1, expa2, ... ] op [ expb1, expb2, ... ]
Such comparisons are expanded into a logic operator form:
(expa1 op expb1) and (expa2 op expb2) and ...
Please, note that because of the mechanical conversion from the vector form to the expanded logic operator form, the following two lines have different meaning:
not ([ expa1, expa2, ... ] = [ expb1, expb2, ... ]) [ expa1, expa2, ... ] != [ expb1, expb2, ... ]
Less-than (<
),
less-or-equal (<=
),
greater-than (>
) and
greater-or-equal (>=
).
Vector comparisons using <
,
>
, etc. operators have
the same precedence as their scalar counterpart.
These are also expanded into the logic form, see
Section 3.5.4.1 above.
Bitwise shift left (a >> b
) and
bitwise shift right (a << b
).
a + b
and a - b
.
a * b
, a / b
and
a % b
.
a ^ b
works as a-to-the-power-of-b.
a!
, the '!' sign used as postfix operator.
Unary plus (+a
), unary minus (-a
),
logical NOT (!a
, '!' used as prefix operator),
bitwise NOT (~a
), prefix increment (++a
)
and prefix decrement (--a
).
Postfix increment (a++
) and decrement
(a--
).
Function calls execute a function on operands:
function(operand[, ...])
. A function name
is a single word known by OpenCReports at the time of parsing,
either as a built-in function, or a user-supplied one.
The function name cannot have a leading dot or be a
domain-qualified identifier.
Implicit multiplication is when two distinct operands are in juxtaposition, in other words they are written side by side without any whitespace. In this case, there is an implied multiplication between them that acts with higher precedence than regular multiplication or division. Implicit multiplication is applicable in these situations:
A numeric constant juxtaposed with an identifier, the numeric constant is the on the left side.
2x
A numeric constant juxtaposed with an expression inside parentheses. The constant can be on either side of the expression.
2(a+b) (a+b)2
An identifier juxtaposed with an expression inside parentheses, the identifier is on the left side of the expression.
x(a+b)
This is only treated as implicit multiplication if the following conditions are met:
the x
identifier
is not a function name at the time
of parsing
there is a single expression inside the parentheses
If any of the conditions below are true, the expression is treated as a function call:
x
is a known
function name
there is no expression inside the parentheses
a series of comma delimited expressions is inside the parentheses
The function call validity is checked against the number
of operands, with a potential parser error. If there's
an ambiguity between function names and identifiers
provided by data sources, it can be avoided by using
dot-prefixed or dot-prefixed and quoted identifiers,
or fully qualified identifiers in the form of
query.identifier
.
An expression inside parentheses juxtaposed with an identifier on the right side.
(a+b)a
Two expressions inside parentheses juxtaposed with each other.
(a+b)(c+d)
Implicit multiplication is NOT applicable in these situations, besides the exceptions already explained above:
An identifier juxtaposed with a numeric constant, the numeric constant is the on the right side.
x2
Since an identifier name may include digits as the second and subsequent characters, the numeric constant, or at least its integer part is simply recognized as part of the identifier name itself according to the token matching. This can also result in syntax errors when not handled with care.
An identifier juxtaposed with another identifier.
ab
The reason is the same as in the preceding case: there is only a single identifier according to token matching.
Parenthesized expressions are always computed first.
Expression parsing works on two levels: token matching and applying grammar. Token matching breaks up the expression string into tokens in a greedy way: without whitepace delimiters, the longest possible token is chosen.
This may lead to slight confusion when coupled with
implicit multiplication. For example, the expression
2e-1e
is broken up into two tokens:
2e-1
juxtaposed with
e
. The first token is interpreted as
a numeric constant using e-notation
(so that it will mean 2 * 10^(-1)
) and
the second is the identifier e
, leading
to the meaning 0.2 * e
. This is
unambiguous for the computer, but can be somewhat confusing
to the the user reading or writing expressions. To avoid
any confusion, don't use implicit multiplication and use
whitespace and parentheses gratituously.
Expression parsing handles precedence and whitespaces. For example, these below do not mean exactly the same:
a++ + ++b a+++++b
The former is obvious, but the latter may be a little
surprising: (a++)++ + b
.
This is how the lexer or token matching works, i.e.
it matches the longest applicable token first.
If a
and b
are
numbers, then the result of both expressions is
a + b + 2
, but the way it's arrived at
is different.
However, the ++
(increment) and
--
(decrement) operators may be
interpreted differently for other types. For example,
if both a
and b
are
of the datetime
type, then the result
also depends on whether one of them is an interval datetime,
and the other (regular) datetime value has valid time or not.
To make the expression unambiguous, whitespace and/or
parenthesis should be used.
Another ambiguous example:
a++b
The above may be interpreted as a + +b
but since no whitespace is used, the tokenizer is free to
interpret it as a++ b
, because
++
is longer than +
,
so the former is matched first as an operator token.
This is a syntax error and expression parsing throws
an error for it.