1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <formula/token.hxx>
11 #include <formula/vectortoken.hxx>
13 #include "compiler.hxx"
14 #include "grouptokenconverter.hxx"
16 using namespace formula
;
18 bool ScGroupTokenConverter::isSelfReferenceRelative(const ScAddress
& rRefPos
, SCROW nRelRow
)
20 if (rRefPos
.Col() != mrPos
.Col())
23 SCROW nLen
= mrCell
.GetCellGroup()->mnLength
;
24 SCROW nEndRow
= mrPos
.Row() + nLen
- 1;
28 SCROW nTest
= nEndRow
;
30 if (nTest
>= mrPos
.Row())
35 SCROW nTest
= mrPos
.Row(); // top row.
44 bool ScGroupTokenConverter::isSelfReferenceAbsolute(const ScAddress
& rRefPos
)
46 if (rRefPos
.Col() != mrPos
.Col())
49 SCROW nLen
= mrCell
.GetCellGroup()->mnLength
;
50 SCROW nEndRow
= mrPos
.Row() + nLen
- 1;
52 if (rRefPos
.Row() < mrPos
.Row())
55 if (rRefPos
.Row() > nEndRow
)
61 SCROW
ScGroupTokenConverter::trimLength(SCTAB nTab
, SCCOL nCol1
, SCCOL nCol2
, SCROW nRow
, SCROW nRowLen
)
63 SCROW nLastRow
= nRow
+ nRowLen
- 1; // current last row.
64 nLastRow
= mrDoc
.GetLastDataRow(nTab
, nCol1
, nCol2
, nLastRow
);
65 if (nLastRow
< (nRow
+ nRowLen
- 1))
66 nRowLen
= nLastRow
- nRow
+ 1;
67 else if (nLastRow
== 0)
74 ScGroupTokenConverter::ScGroupTokenConverter(ScTokenArray
& rGroupTokens
, ScDocument
& rDoc
, ScFormulaCell
& rCell
, const ScAddress
& rPos
) :
75 mrGroupTokens(rGroupTokens
), mrDoc(rDoc
), mrCell(rCell
), mrPos(rPos
)
80 bool ScGroupTokenConverter::convert(ScTokenArray
& rCode
)
83 { // debug to start with:
84 ScCompiler
aComp( &mrDoc
, mrPos
, rCode
);
85 aComp
.SetGrammar(formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1
);
86 OUStringBuffer aAsString
;
87 aComp
.CreateStringFromTokenArray(aAsString
);
92 for (const formula::FormulaToken
* p
= rCode
.First(); p
; p
= rCode
.Next())
94 // A reference can be either absolute or relative. If it's absolute,
95 // convert it to a static value token. If relative, convert it to a
96 // vector reference token. Note: we only care about relative vs
97 // absolute reference state for row directions.
99 const ScToken
* pToken
= static_cast<const ScToken
*>(p
);
100 SCROW nLen
= mrCell
.GetCellGroup()->mnLength
;
101 switch (pToken
->GetType())
105 ScSingleRefData aRef
= pToken
->GetSingleRef();
106 ScAddress aRefPos
= aRef
.toAbs(mrPos
);
109 if (isSelfReferenceRelative(aRefPos
, aRef
.Row()))
112 // Trim data array length to actual data range.
113 nLen
= trimLength(aRefPos
.Tab(), aRefPos
.Col(), aRefPos
.Col(), aRefPos
.Row(), nLen
);
115 // Fetch double array guarantees that the length of the
116 // returned array equals or greater than the requested
119 formula::VectorRefArray aArray
;
121 aArray
= mrDoc
.FetchVectorRefArray(aRefPos
, nLen
);
123 formula::SingleVectorRefToken
aTok(aArray
, nLen
);
124 mrGroupTokens
.AddToken(aTok
);
128 // Absolute row reference.
129 if (isSelfReferenceAbsolute(aRefPos
))
132 formula::FormulaTokenRef pNewToken
= mrDoc
.ResolveStaticReference(aRefPos
);
136 mrGroupTokens
.AddToken(*pNewToken
);
142 ScComplexRefData aRef
= pToken
->GetDoubleRef();
143 ScRange aAbs
= aRef
.toAbs(mrPos
);
145 // Check for self reference.
146 if (aRef
.Ref1
.IsRowRel())
148 if (isSelfReferenceRelative(aAbs
.aStart
, aRef
.Ref1
.Row()))
151 else if (isSelfReferenceAbsolute(aAbs
.aStart
))
154 if (aRef
.Ref2
.IsRowRel())
156 if (isSelfReferenceRelative(aAbs
.aEnd
, aRef
.Ref2
.Row()))
159 else if (isSelfReferenceAbsolute(aAbs
.aEnd
))
162 // Row reference is relative.
163 bool bAbsFirst
= !aRef
.Ref1
.IsRowRel();
164 bool bAbsLast
= !aRef
.Ref2
.IsRowRel();
165 ScAddress aRefPos
= aAbs
.aStart
;
166 size_t nCols
= aAbs
.aEnd
.Col() - aAbs
.aStart
.Col() + 1;
167 std::vector
<formula::VectorRefArray
> aArrays
;
168 aArrays
.reserve(nCols
);
169 SCROW nRefRowSize
= aAbs
.aEnd
.Row() - aAbs
.aStart
.Row() + 1;
170 SCROW nArrayLength
= nRefRowSize
;
173 // range end position is relative. Extend the array length.
174 SCROW nLastRefRowOffset
= aAbs
.aEnd
.Row() - mrPos
.Row();
175 SCROW nLastRefRow
= mrPos
.Row() + nLen
- 1 + nLastRefRowOffset
;
176 SCROW nNewLength
= nLastRefRow
- aAbs
.aStart
.Row() + 1;
177 if (nNewLength
> nArrayLength
)
178 nArrayLength
= nNewLength
;
181 // Trim trailing empty rows.
182 nArrayLength
= trimLength(aRefPos
.Tab(), aAbs
.aStart
.Col(), aAbs
.aEnd
.Col(), aRefPos
.Row(), nArrayLength
);
184 for (SCCOL i
= aAbs
.aStart
.Col(); i
<= aAbs
.aEnd
.Col(); ++i
)
187 formula::VectorRefArray aArray
;
189 aArray
= mrDoc
.FetchVectorRefArray(aRefPos
, nArrayLength
);
191 aArrays
.push_back(aArray
);
194 formula::DoubleVectorRefToken
aTok(aArrays
, nArrayLength
, nRefRowSize
, bAbsFirst
, bAbsLast
);
195 mrGroupTokens
.AddToken(aTok
);
201 ScRangeName
* pNames
= mrDoc
.GetRangeName();
203 // This should never fail.
206 ScRangeData
* pRange
= pNames
->findByIndex(p
->GetIndex());
208 // No named range exists by that index.
211 ScTokenArray
* pNamedTokens
= pRange
->GetCode();
213 // This named range is empty.
216 mrGroupTokens
.AddOpCode(ocOpen
);
218 if (!convert(*pNamedTokens
))
221 mrGroupTokens
.AddOpCode(ocClose
);
225 mrGroupTokens
.AddToken(*pToken
);
229 ScCompiler
aComp(&mrDoc
, mrPos
, mrGroupTokens
);
230 aComp
.SetGrammar(mrDoc
.GetGrammar());
231 aComp
.CompileTokenArray(); // Regenerate RPN tokens.
236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */