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))
67 // This can end up negative! Was that the original intent, or
68 // is it accidental? Was it not like that originally but the
69 // surrounding conditions changed?
70 nRowLen
= nLastRow
- nRow
+ 1;
71 // Anyway, let's assume it doesn't make sense to return a
72 // negative value here. But should we then return 0 or 1? In
73 // the "Column is empty" case below, we return 1, why!? And,
74 // at the callsites there are tests for a zero value returned
75 // from this function (but not for a negative one).
79 else if (nLastRow
== 0)
86 ScGroupTokenConverter::ScGroupTokenConverter(ScTokenArray
& rGroupTokens
, ScDocument
& rDoc
, ScFormulaCell
& rCell
, const ScAddress
& rPos
) :
87 mrGroupTokens(rGroupTokens
), mrDoc(rDoc
), mrCell(rCell
), mrPos(rPos
)
92 bool ScGroupTokenConverter::convert(ScTokenArray
& rCode
, std::vector
<ScTokenArray
*>& rConversionStack
)
95 { // debug to start with:
96 ScCompiler
aComp( &mrDoc
, mrPos
, rCode
);
97 aComp
.SetGrammar(formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1
);
98 OUStringBuffer aAsString
;
99 aComp
.CreateStringFromTokenArray(aAsString
);
104 for (const formula::FormulaToken
* p
= rCode
.First(); p
; p
= rCode
.Next())
106 // A reference can be either absolute or relative. If it's absolute,
107 // convert it to a static value token. If relative, convert it to a
108 // vector reference token. Note: we only care about relative vs
109 // absolute reference state for row directions.
111 SCROW nLen
= mrCell
.GetCellGroup()->mnLength
;
112 switch (p
->GetType())
116 ScSingleRefData aRef
= *p
->GetSingleRef();
117 ScAddress aRefPos
= aRef
.toAbs(mrPos
);
120 if (isSelfReferenceRelative(aRefPos
, aRef
.Row()))
123 // Trim data array length to actual data range.
124 SCROW nTrimLen
= trimLength(aRefPos
.Tab(), aRefPos
.Col(), aRefPos
.Col(), aRefPos
.Row(), nLen
);
125 // Fetch double array guarantees that the length of the
126 // returned array equals or greater than the requested
129 formula::VectorRefArray aArray
;
131 aArray
= mrDoc
.FetchVectorRefArray(aRefPos
, nTrimLen
);
133 if (!aArray
.isValid())
136 formula::SingleVectorRefToken
aTok(aArray
, nLen
, nTrimLen
);
137 mrGroupTokens
.AddToken(aTok
);
141 // Absolute row reference.
142 if (isSelfReferenceAbsolute(aRefPos
))
145 formula::FormulaTokenRef pNewToken
= mrDoc
.ResolveStaticReference(aRefPos
);
149 mrGroupTokens
.AddToken(*pNewToken
);
155 ScComplexRefData aRef
= *p
->GetDoubleRef();
156 ScRange aAbs
= aRef
.toAbs(mrPos
);
158 // Check for self reference.
159 if (aRef
.Ref1
.IsRowRel())
161 if (isSelfReferenceRelative(aAbs
.aStart
, aRef
.Ref1
.Row()))
164 else if (isSelfReferenceAbsolute(aAbs
.aStart
))
167 if (aRef
.Ref2
.IsRowRel())
169 if (isSelfReferenceRelative(aAbs
.aEnd
, aRef
.Ref2
.Row()))
172 else if (isSelfReferenceAbsolute(aAbs
.aEnd
))
175 // Row reference is relative.
176 bool bAbsFirst
= !aRef
.Ref1
.IsRowRel();
177 bool bAbsLast
= !aRef
.Ref2
.IsRowRel();
178 ScAddress aRefPos
= aAbs
.aStart
;
179 size_t nCols
= aAbs
.aEnd
.Col() - aAbs
.aStart
.Col() + 1;
180 std::vector
<formula::VectorRefArray
> aArrays
;
181 aArrays
.reserve(nCols
);
182 SCROW nRefRowSize
= aAbs
.aEnd
.Row() - aAbs
.aStart
.Row() + 1;
183 SCROW nArrayLength
= nRefRowSize
;
186 // range end position is relative. Extend the array length.
187 SCROW nLastRefRowOffset
= aAbs
.aEnd
.Row() - mrPos
.Row();
188 SCROW nLastRefRow
= mrPos
.Row() + nLen
- 1 + nLastRefRowOffset
;
189 SCROW nNewLength
= nLastRefRow
- aAbs
.aStart
.Row() + 1;
190 if (nNewLength
> nArrayLength
)
191 nArrayLength
= nNewLength
;
194 // Trim trailing empty rows.
195 SCROW nRequestedLength
= nArrayLength
; // keep the original length.
196 nArrayLength
= trimLength(aRefPos
.Tab(), aAbs
.aStart
.Col(), aAbs
.aEnd
.Col(), aRefPos
.Row(), nArrayLength
);
198 for (SCCOL i
= aAbs
.aStart
.Col(); i
<= aAbs
.aEnd
.Col(); ++i
)
201 formula::VectorRefArray aArray
;
203 aArray
= mrDoc
.FetchVectorRefArray(aRefPos
, nArrayLength
);
205 if (!aArray
.isValid())
208 aArrays
.push_back(aArray
);
211 formula::DoubleVectorRefToken
aTok(aArrays
, nRequestedLength
, nArrayLength
, nRefRowSize
, bAbsFirst
, bAbsLast
);
212 mrGroupTokens
.AddToken(aTok
);
218 ScRangeName
* pNames
= mrDoc
.GetRangeName();
220 // This should never fail.
223 ScRangeData
* pRange
= pNames
->findByIndex(p
->GetIndex());
225 // No named range exists by that index.
228 ScTokenArray
* pNamedTokens
= pRange
->GetCode();
230 // This named range is empty.
233 mrGroupTokens
.AddOpCode(ocOpen
);
235 if (std::find(rConversionStack
.begin(), rConversionStack
.end(), pNamedTokens
) != rConversionStack
.end())
237 SAL_WARN("sc", "loop in recursive ScGroupTokenConverter::convert");
241 rConversionStack
.push_back(pNamedTokens
);
242 bool bOk
= convert(*pNamedTokens
, rConversionStack
);
243 rConversionStack
.pop_back();
247 mrGroupTokens
.AddOpCode(ocClose
);
251 mrGroupTokens
.AddToken(*p
);
258 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */