Expressions

Example of how the expression parser works

When we have

space-before.optimum="from-parent()"
first the setValue() function of foSpaceBefore property calls the evaluateLength() function of the expression parser.

That function calls the lexical analyser (evaluate() function). The lexical analyser detects three tokens

Function "from-parent"
Operator '('
Operator ')'

That series of tokens has the signature

F()
where "F" stands for "function with 0 or 1 NCName argument".

This signature is recognized by the syntax analyzer, and the syntax analyzer tries to "reduce" it to an unique token.

First, knowing that it's the "from-parent" function, it knows to which FO it applies. Second, the context says that the property type is "space-before" and that the component subtype is "optimum". If an argument had been specified, the hash function would have determined to which property type and which (optional) component subtype the function applied.

That makes it possible to call

property->tokenizeValue(foProperty::optimum);
This tokenizeValue function returns a number token with:
value = optimum of the space-before for that object (as a floating point number, in millimeters)
power of the unit length = 1 (it's a length)

The expression parser then realizes the expression has been completly parsed, and since it has been called with evaluateLength(), it converts it back to a length in micrometers stored into a long integer.

Implementation of property datatypes in the expression parser

<integer> foNumberToken
<number> foNumberToken
<length> foNumberToken
<length-range> foLengthRangeToken
<length-conditional> foLengthConditionalToken
<length-bp-ip-direction> foLengthBpdIpdToken
<space> foSpaceToken
<keep> foKeepToken
<angle> foAngleToken
<color> foColorToken
<shape> foShapeToken
<character> foCharacterToken
<string> foStringToken
<family-name> foStringToken
<name> foNameToken
<country> foNameToken
<language> foNameToken
<script> foNameToken
<id> foNameToken
<idref> (not used so far)
<uri-specification> foUriSpecificationToken
<percentage> if the percentage can be resolved inmediately: foNumberToken (number or length) if it cannot be resolved until layout: foExpression
<time> (not used so far)
<frequency> (not used so far)
(none) foOperatorToken
(none) foFunctionToken

How to compute a percentage in the expression parser

A percentage like

space-start="10%"
is with respect to the inline-progression-dimension of the closest ancestor block-area.

It means that the expression handler to know _what_ to look for, to take a percentage of.

It is a good idea _not_ to precompute this value before calling the expression handler, because in case we would not need it, it would be lost processor time, so we should only compute it on demand.

We shall pass to the expression handler a code telling the formatting object how to compute "a hundred percent":

getIPDOfClosestAncestorBlockArea = 5
This code would be of enumerated type:
foExpression::getPercentage
Alternatively, we could use a pointer to the member function of foFormattingObject that can give the meaning of "a hundred percent":
foFormattingObject::getIPDOfClosestAncestorBlockArea
When the percentage cannot be computed before layout time, the evaluation is deferred, and the percentage is stored "as is" in a foExpression. (Alternatively, we could use a char *).

This expression uses a foPercentageToken to represent the percentage. The expression is "as reduced as possible". For example,

2 * 3%
gets reduced to
6%
but we cannot reduce
2mm + 3%