Expr.pm


NAME

Communiware::Expr - Communiware expression interpreter


SYNOPSIS

        ($code, $type, $is_constant) =
                new Communiware::Expr(
                        atomparser=>sub{$tpl_frag->param(@_)}
                        )->compile_expr(\@expr);
        $result = eval $code;


DESCRIPTION

This module compiles and evaluates arithmetic and logical expressions used in Communiware templates. Expressions are supported in the dynamic elements which explicitly allow them.

Each operand and operator of expression must be passed to dynamic element as separate parameter.

Expressions are interpreted as lists of strings, so if you want to use attribute values, you should use either visualisation time '@' or submit time (in Use, Check, Item) '%' substitution.

Type of the value is derived either from the ontology at compile time, or from its format. Any data can participate in operation, where string operand is required, data should look like number to participate in number operation, and should be in standard Communiware date format ``YYYY.MM.DD HH:MI:SS''.

Date operations are guaranteed to work only in the range between 1.01.1970 and 17.01.2038.

Some dynamic elements (i.e. If) can do some preprocessing on expressions thus allowing for example compare statuses for greater/less.


ARITHMETIC EXPRESSIONS

Arithmetic expressions are allowed in the dynamic elements Subst, Use and Define.

OPERATIONS

Following operations are supported by subst

.
string concatenation

x
string multiplication. Left operand should be a string, and right operand should be an integer. String would be repeated n times

%
Operand formatting. Left argument is value of type number, date, string or richtext, and right is format specification. For numbers and strings any of printf formats are acceptable, for dates - any of formats, acceptable for strftime, for strings - any of formats, acceptable by Communiware::Format::Text::ToInternal. For richtext the options allowed by Communiware::Format::untag_html are provided. Values are html-escaped after formatting.

  • Numeric multiplication. Both operands should be numbers.

/
Numeric (floating-point) division

mod
Modulo operation. Returns reminder of division

div
Integer division

+
Numeric/date addition

For date addition left operand should be date, and right - real number, interpreted as number of days. Date is distinguished from number by presence of more than one point (YYYY.MM.DD HH:MI:SS).

-
Numeric/date substraction

()
Used for grouping of operations

Operation priorities

 1: * x 
 2: + -
 3: %
 4: .
 
=head1 LOGICAL EXPRESSIONS

Logical expressions evaluate to the true and false value, and used in the dynamic elements where certain decision have to be made, i.e If, Check, Item.

They consist of list of elementary condition, joined by logical and and or operators (with possible grouping with parentheses)

Logical expressions are short-evaluated. I.e. if in the some point of evaluation it becomes clear, that following condition wouldn't affect result (i.e. left operand of && is evaluated to false or left operand of || is evaluated to true), rest of expression is not evaluated.

This allows to speed up complex conditions if they contain expensive operations, such as filter invocation.

LOGICAL OPERATORS

There are three logical operators supported (listed in order of priority):

!
Logical not. Negates following condition

&&
Logical and. True if and only if both operands evaluate to true

||
Logical or. False if and only if both operands evaluate to false

Operands of logical operators can be ether elementary conditions, or parenthized logical expressions.

Conditions

There are following types of conditions:

value
False if value is empty string or numeric zero. True otherwise

value = value
True if both values are equal. Numeric comparation is performed if both operats look like number, string comparation otherwise

value != value
value <> value
True if values are not equal.

value < value
value <= value
value > value
value >= value
Various froms of numeric and string comparation

value ~ value
Regular expression matching. True if left operand matches regular expression in right operand. No special synax like // required for regular expression. Matching modifiers are not supported.

Such features of perl regular expressions as character classes \w \s etc and zero-width assertions are supported.

value !~ value
Negative matching. True if left operand doesn't match regular expression in the right operand.

value IN filter specification
True if value is among set of values returned by filter. By default, value of ITEM_ID attribute returned by filter is checked.

<value> can have form

 attrvalue:ATTRNAME

In this case attrvalue will compare not with ITEM_ID, but with ATTRNAME where ATTRNAME is one of possible items attributes. For example if we want to check if there are already an author with given real name we can use expression

 %TITLE:TITLE IN  {ITEM_TYPE='AUTHOR'}

value :=: value
List comparasion. Both operands should be comma-separated lists of values. Evaluates to true if lists contain same elements, regardless of order. Duplicates and empty elements are not counted.


INTERNALS

new

        $expr = new Communiware::Expr(atomparser => sub { $tpl->param(@_) });

Creates new expression object. 'atomparser' parameter is used to provide it with an atom parser callback (usually to template fragment's param() or to posting context's subst_param() method).

throw

        throw("sprintf format", @args);

Throws an exception in a form suitable for handling both in runtime and while compilation. Please use english messages in format.

compile_expr

        $code = compile_expr(\@list);
        ($code, $type, $is_constant) = compile_expr(\@list);

Compiles Communiware expression into perl expression. Compilation stops at first place where operand is followed by non-operator, and remaining list elements are left in list.

Operands are compiled using atomparser closure passed to constructor.

If some of expression operands is scalar reference rather than scalar, it is assumed that it contains already compiled perl expression, not an argument for param method. If it is an array reference, it is assumed to have all the three components - code, type and constantness.

compile_operator

        ($code, $type, $is_constant) = $expr->compile_operator(\@expr, $level);

Compiles start of @expr as an operand of operator of level $level (lower precedence means lower $level). Uses @OPERATORS for a list of operators on each level. Each element of @OPERATORS is an anonymous hash. Its key may be either empty string, or 'operator', or 'operator(type)(type)'. The first form determines arity. 'unary' is interpreted as unary operator, defaults to binary. The third form (number of types corresponds to arity) determines behavior of this operator if operands are of specified Communiware types (use 'UNDEF' for type that is unknown at compile time). The second form is a fallback. The value of second and third forms is an anonymous array whose first element is either a sprintf format (code is generated by sprintf($this_format, @operand_codes)) or a function reference (code is generated by $this_ref-(@operand_codes)>), and whose second element is result type.

gen_polymorph_op2

        @list = gen_polymorph_op2($op);

Returns list for @OPERATORS' element, describing operator whose meaning varies depending on types of arguments, such as '<lt>' or '='. These operators are interpreted as number comparison if both arguments are numbers, string comparison otherwise.

At compilation time we sometimes don't know types in advance. If we cannot determine perl operator at compile time, we generate call to ``intellectual comparison'' function.

That is

        gen_polymorph_op2('=')

returns something like

        '=(NUMBER)(NUMBER)' => ['%s == %s', 'STRING'],
        '=(UNDEF)(NUMBER)' => [q(Communiware::Expr::compare2('=',%s,%s)),
                'STRING'],
        '=(NUMBER)(UNDEF)' => [q(Communiware::Expr::compare2('=',%s,%s)),
                'STRING'],
        '=(UNDEF)(UNDEF)' => [q(Communiware::Expr::compare2('=',%s,%s)),
                'STRING'],
        '=' => ['%s eq %s', 'STRING'],

compare2

        Communiware::Expr::compare2($operator, $arg1, $arg2)

Makes ``intellectual compare'' of its arguments with given operator. That is, if both arguments look like numbers, it is numeric comparison, otherwise it is string comparison.

add_date

  adds given number of days to the date

subtract_dates

returns number of day between two dates

quote

        $string = quote($string);
        $string = quote($string,qr/\\\@/);

Converts string into properly-quoted perl string constant. If second-argument is non null, it should be regular expression, which matches thing, which should be displayed as at-sign.

16 октябрь 2007 13:44