I like the patch and the way RelativeNumericProperty holds and evaluates an expression tree (except my different preference for storing layout information, as discussed). This is really nice and works well:
v = "(((0mpt +(4000mpt +20.0%)) +0mpt) +0mpt)"
[Peter B. West]
Can you describe your expression tree in more detail?
The line above is most likely the toString() on the expression that is the result of a start-indent calculation from [5.3.2].
Each set of parens represent an algebra operation node in a (mostly) binary tree. The expression above is actually stored like this.
v | +-ADD | +--0mpt | +--ADD | +--0mpt | +--ADD | +--ADD | | | +-- 4000mpt | | | +-- %20 of REFERENCE_IPD | +-- 0mpt
The tree is created lazily during the evaluation of expression in the property parser. If both the operands to an operation are absolute, the operation is performed at parse time, but if either one of the operands are relative values, an operation-node is created. The operation node is also considered to be a relative value, so the next operation that involves an operation node will always create a new operation node.
(Note to self: Perhaps it is worthwhile to detect if one of the operands in a ADD and SUB operation is 0? It would perhaps reduce memory for the majority of start-indent expressions).
A node on the operation tree is represented by an instance of fo.expr.RelativeNumericProperty. The code that creates the tree is located in NumericOp and it is called from the PropertyParser.
When a property is retrieved by the LMs, it is the final call to Length.getValue() or Numeric.getNumericValue() that triggers the evaluation of the operation tree. At that time the REFERENCE_IPD value should have been assigned by the LMs to one of the parent fo:elements.