Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : */
9 :
10 : #include <formula/token.hxx>
11 : #include <formula/vectortoken.hxx>
12 :
13 : #include "compiler.hxx"
14 : #include "grouptokenconverter.hxx"
15 :
16 : using namespace formula;
17 :
18 0 : bool ScGroupTokenConverter::isSelfReferenceRelative(const ScAddress& rRefPos, SCROW nRelRow)
19 : {
20 0 : if (rRefPos.Col() != mrPos.Col())
21 0 : return false;
22 :
23 0 : SCROW nLen = mrCell.GetCellGroup()->mnLength;
24 0 : SCROW nEndRow = mrPos.Row() + nLen - 1;
25 :
26 0 : if (nRelRow < 0)
27 : {
28 0 : SCROW nTest = nEndRow;
29 0 : nTest += nRelRow;
30 0 : if (nTest >= mrPos.Row())
31 0 : return true;
32 : }
33 0 : else if (nRelRow > 0)
34 : {
35 0 : SCROW nTest = mrPos.Row(); // top row.
36 0 : nTest += nRelRow;
37 0 : if (nTest <= nEndRow)
38 0 : return true;
39 : }
40 :
41 0 : return false;
42 : }
43 :
44 0 : bool ScGroupTokenConverter::isSelfReferenceAbsolute(const ScAddress& rRefPos)
45 : {
46 0 : if (rRefPos.Col() != mrPos.Col())
47 0 : return false;
48 :
49 0 : SCROW nLen = mrCell.GetCellGroup()->mnLength;
50 0 : SCROW nEndRow = mrPos.Row() + nLen - 1;
51 :
52 0 : if (rRefPos.Row() < mrPos.Row())
53 0 : return false;
54 :
55 0 : if (rRefPos.Row() > nEndRow)
56 0 : return false;
57 :
58 0 : return true;
59 : }
60 :
61 0 : SCROW ScGroupTokenConverter::trimLength(SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCROW nRowLen)
62 : {
63 0 : SCROW nLastRow = nRow + nRowLen - 1; // current last row.
64 0 : nLastRow = mrDoc.GetLastDataRow(nTab, nCol1, nCol2, nLastRow);
65 0 : if (nLastRow < (nRow + nRowLen - 1))
66 0 : nRowLen = nLastRow - nRow + 1;
67 0 : else if (nLastRow == 0)
68 : // Column is empty.
69 0 : nRowLen = 1;
70 :
71 0 : return nRowLen;
72 : }
73 :
74 0 : ScGroupTokenConverter::ScGroupTokenConverter(ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
75 0 : mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos)
76 :
77 : {
78 0 : }
79 :
80 0 : bool ScGroupTokenConverter::convert(ScTokenArray& rCode)
81 : {
82 : #if 0
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);
88 : }
89 : #endif
90 :
91 0 : rCode.Reset();
92 0 : for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
93 : {
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.
98 :
99 0 : const ScToken* pToken = static_cast<const ScToken*>(p);
100 0 : SCROW nLen = mrCell.GetCellGroup()->mnLength;
101 0 : switch (pToken->GetType())
102 : {
103 : case svSingleRef:
104 : {
105 0 : ScSingleRefData aRef = pToken->GetSingleRef();
106 0 : ScAddress aRefPos = aRef.toAbs(mrPos);
107 0 : if (aRef.IsRowRel())
108 : {
109 0 : if (isSelfReferenceRelative(aRefPos, aRef.Row()))
110 0 : return false;
111 :
112 : // Trim data array length to actual data range.
113 0 : SCROW nTrimLen = trimLength(aRefPos.Tab(), aRefPos.Col(), aRefPos.Col(), aRefPos.Row(), nLen);
114 : // Fetch double array guarantees that the length of the
115 : // returned array equals or greater than the requested
116 : // length.
117 :
118 0 : formula::VectorRefArray aArray;
119 0 : if (nTrimLen)
120 0 : aArray = mrDoc.FetchVectorRefArray(aRefPos, nTrimLen);
121 :
122 0 : formula::SingleVectorRefToken aTok(aArray, nLen, nTrimLen);
123 0 : mrGroupTokens.AddToken(aTok);
124 : }
125 : else
126 : {
127 : // Absolute row reference.
128 0 : if (isSelfReferenceAbsolute(aRefPos))
129 0 : return false;
130 :
131 0 : formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefPos);
132 0 : if (!pNewToken)
133 0 : return false;
134 :
135 0 : mrGroupTokens.AddToken(*pNewToken);
136 : }
137 : }
138 0 : break;
139 : case svDoubleRef:
140 : {
141 0 : ScComplexRefData aRef = pToken->GetDoubleRef();
142 0 : ScRange aAbs = aRef.toAbs(mrPos);
143 :
144 : // Check for self reference.
145 0 : if (aRef.Ref1.IsRowRel())
146 : {
147 0 : if (isSelfReferenceRelative(aAbs.aStart, aRef.Ref1.Row()))
148 0 : return false;
149 : }
150 0 : else if (isSelfReferenceAbsolute(aAbs.aStart))
151 0 : return false;
152 :
153 0 : if (aRef.Ref2.IsRowRel())
154 : {
155 0 : if (isSelfReferenceRelative(aAbs.aEnd, aRef.Ref2.Row()))
156 0 : return false;
157 : }
158 0 : else if (isSelfReferenceAbsolute(aAbs.aEnd))
159 0 : return false;
160 :
161 : // Row reference is relative.
162 0 : bool bAbsFirst = !aRef.Ref1.IsRowRel();
163 0 : bool bAbsLast = !aRef.Ref2.IsRowRel();
164 0 : ScAddress aRefPos = aAbs.aStart;
165 0 : size_t nCols = aAbs.aEnd.Col() - aAbs.aStart.Col() + 1;
166 0 : std::vector<formula::VectorRefArray> aArrays;
167 0 : aArrays.reserve(nCols);
168 0 : SCROW nRefRowSize = aAbs.aEnd.Row() - aAbs.aStart.Row() + 1;
169 0 : SCROW nArrayLength = nRefRowSize;
170 0 : if (!bAbsLast)
171 : {
172 : // range end position is relative. Extend the array length.
173 0 : SCROW nLastRefRowOffset = aAbs.aEnd.Row() - mrPos.Row();
174 0 : SCROW nLastRefRow = mrPos.Row() + nLen - 1 + nLastRefRowOffset;
175 0 : SCROW nNewLength = nLastRefRow - aAbs.aStart.Row() + 1;
176 0 : if (nNewLength > nArrayLength)
177 0 : nArrayLength = nNewLength;
178 : }
179 :
180 : // Trim trailing empty rows.
181 0 : SCROW nRequestedLength = nArrayLength; // keep the original length.
182 0 : nArrayLength = trimLength(aRefPos.Tab(), aAbs.aStart.Col(), aAbs.aEnd.Col(), aRefPos.Row(), nArrayLength);
183 :
184 0 : for (SCCOL i = aAbs.aStart.Col(); i <= aAbs.aEnd.Col(); ++i)
185 : {
186 0 : aRefPos.SetCol(i);
187 0 : formula::VectorRefArray aArray;
188 0 : if (nArrayLength)
189 0 : aArray = mrDoc.FetchVectorRefArray(aRefPos, nArrayLength);
190 :
191 0 : aArrays.push_back(aArray);
192 : }
193 :
194 0 : formula::DoubleVectorRefToken aTok(aArrays, nRequestedLength, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
195 0 : mrGroupTokens.AddToken(aTok);
196 : }
197 0 : break;
198 : case svIndex:
199 : {
200 : // Named range.
201 0 : ScRangeName* pNames = mrDoc.GetRangeName();
202 0 : if (!pNames)
203 : // This should never fail.
204 0 : return false;
205 :
206 0 : ScRangeData* pRange = pNames->findByIndex(p->GetIndex());
207 0 : if (!pRange)
208 : // No named range exists by that index.
209 0 : return false;
210 :
211 0 : ScTokenArray* pNamedTokens = pRange->GetCode();
212 0 : if (!pNamedTokens)
213 : // This named range is empty.
214 0 : return false;
215 :
216 0 : mrGroupTokens.AddOpCode(ocOpen);
217 :
218 0 : if (!convert(*pNamedTokens))
219 0 : return false;
220 :
221 0 : mrGroupTokens.AddOpCode(ocClose);
222 : }
223 0 : break;
224 : default:
225 0 : mrGroupTokens.AddToken(*pToken);
226 : }
227 : }
228 :
229 0 : ScCompiler aComp(&mrDoc, mrPos, mrGroupTokens);
230 0 : aComp.SetGrammar(mrDoc.GetGrammar());
231 0 : aComp.CompileTokenArray(); // Regenerate RPN tokens.
232 :
233 0 : return true;
234 : }
235 :
236 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|