Using &* can be problematic if the pointer is null. In this case it
probably doesn’t matter, but using get() is probably easier to
understand anyway. This also paves the way for a later compiler plugin
to check for this.
Change-Id: I0ba29f530c648782d7d6af8225a2eb6d5c28b5b9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211844
Tested-by: Jenkins
Reviewed-by: Neil Roberts <nroberts@libreoffice.org>
The operand of an @ or of a union list ends where an operator further
out ends it, and the whitespace in front of that operator was still
inside it. So the blank was written inside the call parentheses, and
since a range ending in whitespace is no longer one parenthesised
group, the operand got a second pair of parentheses on top of the
ones it had - @(A1) + 1 came out as _xlfn.SINGLE((A1) )+ 1.
The wrapper now ends in front of those tokens. A blank before the #
stays with the operand, that one is the operator being rewritten.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Ie6fe2df4e3e05b0ef845ebdb8a1aedb54b3f2a66
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/10851
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit fd39c3a52d1cab7c0429bb98c4749bbfed088e6a)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210478
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
The formula writer substitutes an error constant for anything that has
no spelling in the target format, and it took that string from the
native symbol table. That table is translated, so a build in another
language wrote a translated "#REF!" into the saved formula, where only
the English spelling reads back. It now takes the string from the
table of the grammar being written, which changes nothing for the
native grammar.
Reading had a gap of its own. The OOXML table had a second "#REF!" row
for the stop opcode, and the symbol map keeps the first spelling it
finds in opcode order, so that row shadowed the error constant and a
bare #REF! read from a file gave #NAME?. Nothing needs a spelling for
the stop opcode, so the row is gone.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Idbe8ce87d6ad6346106622379ff59908a36eb7f7
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/10163
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 75160522f6a9de4999b824725326475ba8d713f1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210313
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
The compiler decides whether a blank is the intersection operator by
looking at the tokens on either side. Both parenthesis tokens have the
separator type, which those checks read as "not a reference", so
=SUM((A1:B1,A2:B2) A1:A2) didn't parse even though it should intersect
the list with the range. The parentheses are now accepted by their
opcode, and so is a reference list built from a converted separator on
either side.
The blank also keeps the parenthesis after it a group. An operand
followed by a parenthesis normally opens an argument list for a
callable, but with the intersection blank in between there is no call,
so ocCall is not injected. A name in front still calls either way.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I8e4b5fb7136419b4e937c8abb521711a8d418af8
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/10162
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit b12a7af0e1aab942aa5014b799a96271d03c472f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210305
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
A reference list is built from the separator between two parts of a
parenthesised expression, and which parts join was decided from the
opcodes at the top of their compiled code. That was wrong both ways:
INDEX returns a reference but wasn't counted, so (INDEX(A1:A3,1),B1)
fell apart, while (F25, F26%) didn't parse at all even though it
should give #VALUE!.
The left part now has to end in a reference or an opcode that returns
one, INDEX among them. The right part joins if it starts with one, or
with a nested list, IF, CHOOSE, a lookup, the @ operator or an error
constant. What it then makes of that reference is the calculation's
business.
A part starting with anything else leaves the separator a separator
and the formula doesn't parse, which is what the producing
application refuses at its formula bar too.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: If65d2f0f9cc599729564cfc5369c0479b07c93e8
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/10160
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 50ddf65b640a9cb88aea56be4367a3e44152c230)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210303
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
The # postfix operator was parsed at the same level as the percent
sign, which is looser than the prefix operators. Because of this
=@A1# compiled to the spill range of an implicit intersection and
=-A1# to the spill range of a negated value. Neither of those means
anything, and OOXML writes the # around the reference alone in both
cases.
The # is now parsed right after the factor it follows, tighter than any
operator that can come before it. A whole range reference goes inside,
because the lexer reads A1:A3 as a single reference. The percent sign
stays above the reference operators, so =A1%# leaves the # with nothing
to bind to and doesn't parse, and the export drops such a # (OOXML has
no spelling for it either).
A blank between two operands is only the intersection operator if both
sides yield a reference. The # does, so the checks that keep the blank
alive and that keep the operator once the operands are known had to be
told about it.
The interpreter passes the spill range on as a matrix that carries the
range it was read from. The intersection, range and union operators
only took references and refused that, so PopReferenceOperand now
hands them the carried range as a double reference.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I1a587bf291ff639b326a366b8efc332106eb5fd3
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/10156
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit c589c34aaec00d60fc47f1933762b105f9d22de3)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210293
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
OOXML writes @ and # as calls and a reference union as a parenthesised
list, so for each of them we need to know how far the sub-expression
under it reaches. CreateStringFromTokenArray worked that out from the
text it had already written. The problem with this is that every pair
it spliced in shifted all the offsets that were still waiting behind
it, so it kept breaking.
Instead of patching the text, OOXMLRewriter builds a second
token array in the shape OOXML spells out and the writer walks that as
it stands. The call names and the parentheses are ordinary tokens, so
there is nothing to splice and no offsets to keep track of. It is the
same trick RewriteMissing already plays a few lines further up, and it
means the input and the output can be looked at side by side.
The # changes place, from behind its operand to a call in front of it,
so it gets an opcode of its own. _xlfn.ANCHORARRAY spells ocAnchorArray
now, and ocSpill keeps the native postfix spelling with no OOXML one at
all, so the postfix form cannot end up in a file by accident. The
import already rewrote the call back into the postfix operator and now
recognises it by opcode instead of by position. The @ stays
ocSingleValue, it is already in front of its operand so only the
parentheses are new.
The OFFSET() literal argument is swapped for the reference error in
the same pass, instead of the writing loop jumping over tokens.
A unit test drives the rewrite on its own: token array in, token array
out, one case per shape. The shapes that end up with nothing to wrap
are in there too - a lone @, one with a missing argument, and text that
never parsed - since those are the ones where dropping a token is the
only change.
Also drop the dead "@" and "#" rows from the OOXML symbol table, the
rows above them already have _xlfn.SINGLE and _xlfn.ANCHORARRAY.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I63944fb85b5c4388f304f7d94afd0b4f347d7782
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/10155
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 4feac84950f5b524d99e277481de50f7b45a8d2f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210292
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
The _xlfn.SINGLE and _xlfn.ANCHORARRAY wrappers go into the formula
text once the operand they enclose stands in the buffer, and each
splice moves the text behind it along. Several of the recorded
starts did not move with it, so =SUM( @A1#) saved as
SUM(__xlfn.SINGLE(xlfn.ANCHORARRAY( A1))), and A1~-B2# and @-A1%#
came out wrong in the same way.
Whitespace ahead of a scope or of an expression is no longer part of
it, so the starts the wrappers and the union list use begin behind
the blank.
The spilled-range splice pulls an @ that begins inside its wrapper
back to the wrapper's own start, so the @ takes the whole wrapper as
its operand.
The union list's parenthesis and the @ splice both move the start of
the expression they go in front of, so a postfix operator behind
them still finds where its operand begins.
A scope's parentheses count as taken when a wrapper begins ahead of
the scope's text, as they already did when one begins exactly at it.
The writer of the pending @ wrappers asserts that they stand in the
order their operands begin. That order is what keeps the starts
still waiting correct, and each of these bugs broke it.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I87ca7c67be9d2f11ca34661a79401a2fa1c60bbe
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/9638
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 3d52e137f229d87bc5633dc7966bace3044f1c3a)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/209504
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
XLSX writes the # operator as _xlfn.ANCHORARRAY around its operand.
The walk spliced that wrapper at the start of the last factor, but the
grammar puts the # above the range, intersection and union operators,
so all of those belong inside the operand. A1~B2# came out as
(A1,_xlfn.ANCHORARRAY(B2)) and A1:INDEX(B1:B10;5)# as
A1:_xlfn.ANCHORARRAY(INDEX(B1:B10,5)).
Each parenthesis scope already records where its union-level
expression begins, which is in front of every operator the # binds
looser than. The wrapper splices there instead, and an open union list
takes its own parentheses first.
Nothing reads the separate stack of factor starts now. Its depth
matched the scope stack's, so that stack carries it and the vector is
gone.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I6fd212a0e97ee40ce04c27a758f78669d3fce5f8
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/9309
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 82f4f2386f5d752a890de306fb89c314c4d87a1f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/209412
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
OOXML writes the union operator as the same comma that separates
function arguments, so a union with no parentheses of its own fell
apart on save: SUM(A1~B2) became SUM(A1,B2), which reads as two
arguments, and INDEX(A1:B3~D1:E3;1;1;2) changed its meaning even on
Calc's own reload. A union already inside a parenthesised group was
safe, since the group's tokens are kept.
The walk now records where the union-level expression of each
parenthesis scope starts. The first union operator opens a list
there, and the list takes one pair of parentheses when the
expression ends: at a looser operator, an argument separator, the
parenthesis that closes the scope, or the end of the formula.
A list that fills a grouping parenthesis exactly keeps that pair, so
a formula holds its shape over repeated round trips. Two kinds of
parenthesis cannot be reused that way: the one behind AND, OR or the
call operator, which opens an argument list rather than a group, and
one that an @ wrapper beginning at the same place has already taken.
The group check behind the @ wrapper refuses a group with a comma
directly inside it, passing over the commas an inline matrix or a
bracketed reference carries. Text that no parse could read takes no
parentheses at all, so a list reaching such text drops its pair.
Unit tests pin the written string for each union shape, and the
positions the inserted parenthesis shifts. A round-trip test checks
the saved XML and the reloaded formulas and values.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I970f3b4ecea680f6e70d146a2f1608c4adff9c1f
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/9308
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit dd8104342d7147f07006bebb1dbeec60b48250f6)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/209411
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
The @ operand walk on OOXML save took the token behind the @ as the
whole operand, so any operand longer than one token was cut apart by
the wrapper: a leading sign, a structured table reference, a range
built with the range operator, and a nested @ or # inside an
argument list all left parts of themselves outside.
The @ now writes no text of its own. The main token loop notes where
the wrapper has to go and which parenthesis scope the operand lives
in, and splices _xlfn.SINGLE(...) in once the operand ends. The #
splice already worked that way, so there is one walk with one set of
special cases and no recursion.
Prefix signs and whitespace go inside the wrapper with the operand,
and a sign moves the factor start past itself, so a # wraps the
reference it follows and leaves the sign outside. Table reference
brackets scope like parentheses, which keeps a multi-item reference
whole. AND and OR are written as a name with an argument list, so
such a name does not end the operand either and the whole call stays
inside.
An operand that writes no text leaves the wrapper out. One that is
exactly one parenthesised group lends its parentheses to the
wrapper, so a saved formula keeps its shape over round trips. Text
that never parsed takes no wrapper and drops a # behind it, the way
an ODF save leaves the @ out.
The error strings for tokens the writer cannot spell out sit in
AppendTokenOrError, which tests the cheap conditions first. The
whitespace opcode test moved to opcode.hxx as isWhitespaceOpCode,
replacing the private copies, and the operator range tests join it
there as isUnaryOperatorOpCode and isBinaryOperatorOpCode. Unit
tests pin the saved output for each operand shape.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I9b6c12bbc8d0ddb9efa043a2364d13c4699e7bd5
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/9290
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 2b8d9c58e8f7b5f138d44f41d756421c3f7932cd)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/209393
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
The sequence for LAMBDA in the RPN code is now:
[0] ocLambda, svJump
[1] ocPush, svStringName (parameter name)
[2] ocSep, svSep
(Repeat [1] and [2] for each parameter)
[3] (body code)
[4] ocClose, svSep
[5] (code after LAMBDA expression)
Jumps in the ocLambda point to [0], each [2], and [4], which means
there are two more jumps than parameters.
For example:
=LAMBDA(x;y;x+y)(3;4)
generates the following RPN code:
index opcode type (data)
[0] ocLambda svJump ({4,0,2,4,8})
[1] ocPush svStringName ("x")
[2] ocSep svSep
[3] ocPush svStringName ("y")
[4] ocSep svSep
[5] ocPush svStringName ("x")
[6] ocPush svStringName ("y")
[7] ocAdd svByte
[8] ocClose svSep
[9] ocPush svDouble (3.0)
[10] ocPush svDouble (4.0)
[11] ocCall svByte (3)
The first parameter is in [1], the second is in [3], the body is
in [5]-[7], and [9] is where the code resumes after the LAMBDA.
Change-Id: I4dc871893f47ebbd4dad9cc02ac3efe0ca6ca883
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207973
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
The OOXML format marks an optional LAMBDA parameter with the _xlop.
prefix in the parameter list, while the body refers to the same
parameter through the _xlpm. prefix. Calc recognised only _xlpm., so an
optional parameter kept its prefix, did not match the bare name used in
the body, and lost the mark that made it optional. It failed to bind,
and a call that left it out reported an error.
Recognise _xlop. as a parameter marker and strip it to the bare name, so
the declaration and the body references match. Carry the optional mark
onto the parameter token so the compiled code treats it the same way as
the native square-bracket form.
Write an optional parameter back with the marker the grammar uses: the
_xlop. prefix in OOXML and square brackets in the native grammars.
Add a test that imports an optional parameter in the OOXML form and
checks that ISOMITTED sees it as omitted and that concatenating it
yields the other operand.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Ia1df0fa6ca498f4c607507b3a865b3b367e5c11a
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5782
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit f198d7a984654aabd5e988d3c327da5552bc68e0)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207891
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
LAMBDA now supports optional parameters with the [name] syntax; all
such parameters must appear after all required parameters in the
parameter list.
Optional parameters use svMissing, for compatibility with ISOMITTED.
Change-Id: Ice026eeb6937dadd3b1ffd8c07e0d3ce88de9afc
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207392
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
XLSX stores the # spilled-range operator as the prefix call
_xlfn.ANCHORARRAY(<ref>). The exporter emitted the bare #
glyph, which older readers reject.
The operand is already in the buffer when the parse walk
reaches ocSpill, so CreateStringFromTokenArray keeps a
per-parenthesis-depth stack of where the current factor
began. ocSpill splices _xlfn.ANCHORARRAY( at that position
and closes at the buffer's end.
For =@A1# the # binds tighter than @, giving the nested form
_xlfn.SINGLE(_xlfn.ANCHORARRAY(A1)). EmitSingleValueOperandOOXML
splices ANCHORARRAY around the operand and consumes the
trailing ocSpill, so the main loop does not wrap it again in
the wrong order.
Tests check the ANCHORARRAY form in the saved XML and
round-trip an imported spill formula through save and reload.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I9e92350d2574adeebf44fae903ee32dd63654d7c
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5789
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 89715a92489305230b52f2874d768dc117a71eee)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207907
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
A1# is the postfix counterpart of the @ prefix. When A1 is
the origin of a dynamic-array formula spilled into A1:A4, A1#
refers to the whole spill range, so SUM(A1#) totals the four
values and ROWS(A1#) returns 4.
The new opcode ocSpill sits in the unary-operator range. The
tokenizer produces it from a bare # after a reference or
value. Otherwise # stays the start of a #REF! or #NAME!
token. The compiler routes it through PostOpLine so it
follows its operand in the RPN.
ScSpilledRange pushes the spill range as an ScMatrixRangeToken
so aggregating functions see the whole range, and ISREF
reports it as a reference. A master yields its matrix. A
plain number, string, or non-master matrix slot yields the
the cell value.
A freshly typed =A1# counts as an array result, so it
promotes to a dynamic-array master and spills again. A cell
that does not promote collapses the range by implicit
intersection to the row-aligned value, or #VALUE! outside the
range, keeping that cell's number format.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Idf2752af3f7575f6bc95b940344aa365415e4a2f
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5785
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 9b97b0fc91bce4b8726ea210347e8ea84270e148)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207904
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
The @ operator collapses an array operand to its upper-left
value. A function operand like SEQUENCE pushes a matrix and @
collapses it. A range arithmetic operand like (B2:B3+0) does
implicit intersection first and hands @ a scalar, so @ has
nothing to collapse.
Mark @'s operand as ForceArray in the parameter classifier and
wrap UnaryLine in a CurrentFactor scope so the classification
reaches the nested operators. Range arithmetic inside @ then
materialises as a matrix and reaches @ for the upper-left pick.
testSingleValueOperator covers @ on a range expression and a
chained @ binary.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I7f59bfa1efbceeceb9a3d7f71a0243e9a521b24a
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5517
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 4148cbecbdaa3164c53d3869252a3ca714ba5726)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207868
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Add BYCOL(tdf#164508), BYROW(tdf#164509), MAKEARRAY(tdf#164511),
MAP(tdf#164512), REDUCE(tdf#164513), SCAN(tdf#161428) formula
functions, which are usually used together with LAMBDA and are
important for interoperability with other Office suites.
Change-Id: I7eb5a992a113638fdadf0cf61592c082094fb44f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205979
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
The OOXML spec writes =@(expr) as =_xlfn.SINGLE(expr). Calc
emitted the bare @ glyph on save and dropped the wrapper on
load, so =@(F3:F5+0) fell back to a non-array context after a
round trip and lost the authored value.
Map "_xlfn.SINGLE" to ocSingleValue in the OOXML symbol
table. The regular exporter walk now spells ocSingleValue as
"_xlfn.SINGLE" and the import compiler recognises the
wrapper, so a parenthesised operand round-trips with no
further work. A small exporter branch wraps bare and
function-call operands in the wrapper's own parentheses.
OOXML files in the wild put the @ operand inside a redundant
parenthesis pair, _xlfn.SINGLE((expr)). A post-compile pass
on import drops the inner pair so the cell reads back as
=@(expr). The helper takes a trigger-opcode list for reuse.
testSingleOperatorXlsxRoundTrip covers the export path,
testIntersectionOperatorXlsxRoundTrip covers the import strip
from a fixture file.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I2648da125945295fd8548842aba9c82978d96aa9
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5573
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 5ac9db1f563bbde01f9e24fc9bbb8c3599eb0c06)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207789
Tested-by: Jenkins
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Removed LET from sc/README.md's list of functions supporting
wildcards and regular expressions, since it doesn't interact
with either.
Changed LET's return type from ForceArrayReturn to Value, since
it usually doesn't return an array.
Change-Id: I99168d274483ddea5ba338d4e019cf433fe88c45
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205977
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Import classifies each formula cell:
- Plain non-array, no coext:spill: the import-time walk over
the freshly compiled RPN decides if the formula intends an
array. If yes, prepend @ at the front of the parse and at
the back of the RPN.
- Plain non-array + coext:spill="true": a master saved while in
spill state. Comes back at 1x1 with the dynamic flag, the
position marked spilled. The next interpret re-checks the
blockers.
- Array formula (matrix dims): static array master by default.
coext:spill="true" promotes it to a dynamic-array master.
Legacy Ctrl+Shift+Enter (CSE) arrays without the marker keep
their static iteration-and-pad behaviour.
Export reverses:
- ODF always strips @ on save. The @ is an in-memory marker
only. OOXML and the UI grammar keep it.
- Dynamic master: coext:spill="true" in extended ODF, matrix
dims as before. In spill state, write as plain non-array with
coext:spill="true".
- Static array master: matrix dims, no coext:spill.
GetFormula skips the {} wrapping for dynamic-array masters so
they read back as plain formulas. Static array masters keep {}.
XML_SPILL is added to the xmloff token machinery and the ODF
extension schema (OpenDocument-v1.4+libreoffice-schema.rng)
gains coext:spill on table-cell.
Tests cover each import shape, the FODS export of regular and
spilled masters, the @ insertion on CompileXML, and the @
stripping at the formula-compiler level. ArrayFormulasStatic.ods
is a legacy fixture whose B1 = AND(C4:C52) summarises 49 per-row
value checks. The test runs the grid on import and after an ODS
round trip and confirms plain bare-range cells gain @ while the
five matrix masters stay static, keep their {} wrapping, and
get no coext:spill in the saved XML.
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Ib8ae345528185c824415ec5d039b6d5cf0d7eac8
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4663
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit a21f6a3a0eae72fef90576d249d96dc00beeb2c5)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207171
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
Grow or shrink a matrix formula's declared dimensions to match its
interpreted result size. With this, clearing a blocker lets the
array spill across its full range; shrinking the source data
removes the stale trailing cells. Blocking an already-expanded
array collapses it back to the origin with #SPILL!.
Deferred resize queue: inserting or deleting cells inline from
Interpret (or during grid-repaint iteration) would invalidate the
caller's iterator. Queue resizes in the document and drain them
from safe points, guarded by a MatrixResizeGuard helper around
each cell-iteration scope.
Change-Id: I74376427e707fd84c36034fe6a64105e4a5f74fa
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1817
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 76b6825e4d237869cb32889b250277be693a2c5f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205686
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Add a compile-time flag on FormulaTokenArray for formulas that use
a dynamic array function (UNIQUE, FILTER, SORT, SORTBY, SEQUENCE,
RANDARRAY, DROP, EXPAND, HSTACK, VSTACK, TAKE, CHOOSECOLS,
CHOOSEROWS, TEXTSPLIT, TOCOL, TOROW, WRAPCOLS, WRAPROWS). Set by
the compiler when such an opcode appears. Later commits consume
this flag to decide whether a matrix formula is eligible for spill
or auto-resize.
Also fix GetMatrixFormulaCellToken - it used to hide the matrix
token whenever a result error was set, because GetType() returns
svError. Inspect mpToken directly so the token survives error
state. Later commits need the matrix dimensions of a #SPILL! cell
to be readable.
Change-Id: I63c196553762c77b9a64321a2fe9359ee06f6944
Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1815
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit 1ea485c5df618a7ff10c0b8b135d537ce06d94ed)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205684
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
similar to
commit f47fc9a67f16a3da1e5cbcc8b821682298ec90b3
reduce ScRefListToken virtual calls
Push the GetIndex() method down to the only subclasses
that actually use it.
And take the chance to rename them to something more meaningful.
Introduce an inbetween ScExternalToken class to represent
tokens that have an external file id.
Change-Id: If45e87a5bb66aeb1c65d82121b430b886b53f20b
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/955
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Noel Grandin <noel.grandin@collabora.com>
(cherry picked from commit 7705899fa7bca501f331070f7969374fcf5f52e9)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205576
Reviewed-by: Julien Nabet <serval2412@yahoo.fr>
Tested-by: Jenkins
similar to
commit f47fc9a67f16a3da1e5cbcc8b821682298ec90b3
reduce ScRefListToken virtual calls
Push the GetString() methods down to the only subclasses
that actually use it.
We change the inheritance hierarchy a little here
-class FORMULA_DLLPUBLIC FormulaStringOpToken final : public FormulaByteToken
+class FORMULA_DLLPUBLIC FormulaStringOpToken final : public FormulaStringToken
because FormulaStringOpToken and FormulaStringToken share
a type svString which makes it hard to decide which subclass we
are handling.
So now we can check for GetType() == svString and then
cast to FormulaStringToken safely.
Change-Id: I3f087d65a2297b2d8fb5213e81987e0001bc1c62
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/1152
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Noel Grandin <noel.grandin@collabora.com>
(cherry picked from commit 8710f98c1565b1d8ecbbbec743b29bcbb38c5ce2)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205569
Reviewed-by: Julien Nabet <serval2412@yahoo.fr>
Tested-by: Julien Nabet <serval2412@yahoo.fr>
similar to
commit f47fc9a67f16a3da1e5cbcc8b821682298ec90b3
reduce ScRefListToken virtual calls
Push the GetDoubleRef() methods down to the only subclasses
that actually use it.
Which means we can return a ref instead of a pointer,
since we now never return nullptr.
Change-Id: I4dfce551e985fe20db00d3a0694ed99f20f87731
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/1050
Reviewed-by: Noel Grandin <noel.grandin@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit 9aab43b4e3a68cd833eddfdd11086f03e55f2c1a)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205508
Reviewed-by: Julien Nabet <serval2412@yahoo.fr>
Tested-by: Jenkins