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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef INCLUDED_FORMULA_TOKENARRAY_HXX
21 #define INCLUDED_FORMULA_TOKENARRAY_HXX
26 #include <type_traits>
27 #include <unordered_set>
28 #include <unordered_map>
31 #include <formula/ExternalReferenceHelper.hxx>
32 #include <formula/formuladllapi.h>
33 #include <formula/opcode.hxx>
34 #include <formula/token.hxx>
35 #include <o3tl/typed_flags_set.hxx>
36 #include <rtl/ustring.hxx>
37 #include <sal/types.h>
39 namespace com::sun::star
{
40 namespace sheet
{ struct FormulaToken
; }
43 namespace com::sun::star::uno
{ template <typename
> class Sequence
; }
44 namespace formula
{ class FormulaTokenArray
; }
49 class SharedStringPool
;
53 // RecalcMode access only via TokenArray SetExclusiveRecalcMode...() /
56 // Only one of the exclusive bits can be set and one must be set,
57 // handled by TokenArray SetExclusiveRecalcMode...() methods.
58 // Exclusive bits are ordered by priority, AddRecalcMode() relies on that.
59 enum class ScRecalcMode
: sal_uInt8
61 ALWAYS
= 0x01, // exclusive, always
62 ONLOAD_MUST
= 0x02, // exclusive, always after load
63 ONLOAD_ONCE
= 0x04, // exclusive, once after load, import filter
64 ONLOAD_LENIENT
= 0x08, // exclusive, lenient after load (eg. macros not always, aliens, ...)
65 NORMAL
= 0x10, // exclusive
66 FORCED
= 0x20, // combined, also if cell isn't visible, for macros with side effects
67 ONREFMOVE
= 0x40, // combined, if reference was moved
68 EMask
= ALWAYS
| ONLOAD_MUST
| ONLOAD_LENIENT
| ONLOAD_ONCE
| NORMAL
// mask of exclusive bits
72 template<> struct typed_flags
<ScRecalcMode
> : is_typed_flags
<ScRecalcMode
, 0x7f> {};
78 class FORMULA_DLLPUBLIC MissingConvention
83 FORMULA_MISSING_CONVENTION_PODF
,
84 FORMULA_MISSING_CONVENTION_ODFF
,
85 FORMULA_MISSING_CONVENTION_OOXML
87 explicit MissingConvention( Convention eConvention
) : meConvention(eConvention
) {}
88 bool isPODF() const { return meConvention
== FORMULA_MISSING_CONVENTION_PODF
; }
89 bool isODFF() const { return meConvention
== FORMULA_MISSING_CONVENTION_ODFF
; }
90 bool isOOXML() const { return meConvention
== FORMULA_MISSING_CONVENTION_OOXML
; }
91 Convention
getConvention() const { return meConvention
; }
93 Convention meConvention
;
96 class FORMULA_DLLPUBLIC MissingConventionODF
: public MissingConvention
99 explicit MissingConventionODF( bool bODFF
) :
100 MissingConvention( bODFF
?
101 MissingConvention::FORMULA_MISSING_CONVENTION_ODFF
:
102 MissingConvention::FORMULA_MISSING_CONVENTION_PODF
)
105 // Implementation and usage only in token.cxx
106 inline bool isRewriteNeeded( OpCode eOp
) const;
109 class FORMULA_DLLPUBLIC MissingConventionOOXML
: public MissingConvention
112 explicit MissingConventionOOXML() : MissingConvention( MissingConvention::FORMULA_MISSING_CONVENTION_OOXML
) {}
113 // Implementation and usage only in token.cxx
114 static inline bool isRewriteNeeded( OpCode eOp
);
117 typedef std::unordered_set
<OpCode
, std::hash
<std::underlying_type
<OpCode
>::type
> > unordered_opcode_set
;
119 class FORMULA_DLLPUBLIC FormulaTokenArrayStandardRange
122 FormulaToken
** mpBegin
;
123 FormulaToken
** mpEnd
;
126 FormulaTokenArrayStandardRange(FormulaToken
** pBegin
, sal_uInt16 nSize
) :
128 mpEnd(pBegin
+ nSize
)
132 FormulaToken
** begin() const
137 FormulaToken
** end() const
143 class FORMULA_DLLPUBLIC FormulaTokenArrayReferencesIterator
146 FormulaToken
** maIter
;
147 FormulaToken
** maEnd
;
151 while (maIter
!= maEnd
)
153 switch ((*maIter
)->GetType())
157 case svExternalSingleRef
:
158 case svExternalDoubleRef
:
166 enum class Dummy
{ Flag
};
168 FormulaTokenArrayReferencesIterator(const FormulaTokenArrayStandardRange
& rRange
, Dummy
) :
169 maIter(rRange
.end()),
175 FormulaTokenArrayReferencesIterator(const FormulaTokenArrayStandardRange
& rRange
) :
176 maIter(rRange
.begin()),
182 FormulaTokenArrayReferencesIterator
operator++(int)
184 FormulaTokenArrayReferencesIterator
result(*this);
189 FormulaTokenArrayReferencesIterator
const & operator++()
191 assert(maIter
!= maEnd
);
197 FormulaToken
* operator*() const
202 bool operator==(const FormulaTokenArrayReferencesIterator
& rhs
) const
204 return maIter
== rhs
.maIter
;
207 bool operator!=(const FormulaTokenArrayReferencesIterator
& rhs
) const
209 return !operator==(rhs
);
212 static FormulaTokenArrayReferencesIterator
endOf(const FormulaTokenArrayStandardRange
& rRange
)
214 return FormulaTokenArrayReferencesIterator(rRange
, Dummy::Flag
);
218 class FORMULA_DLLPUBLIC FormulaTokenArrayReferencesRange
221 const FormulaTokenArray
& mrFTA
;
224 FormulaTokenArrayReferencesRange(const FormulaTokenArray
& rFTA
) :
229 FormulaTokenArrayReferencesIterator
begin();
231 FormulaTokenArrayReferencesIterator
end();
234 class FORMULA_DLLPUBLIC FormulaTokenArray
237 std::unique_ptr
<FormulaToken
*[]> pCode
; // Token code array
238 FormulaToken
** pRPN
; // RPN array
239 sal_uInt16 nLen
; // Length of token array
240 sal_uInt16 nRPN
; // Length of RPN array
241 FormulaError nError
; // Error code
242 ScRecalcMode nMode
; // Flags to indicate when to recalc this code
243 bool bHyperLink
:1; // If HYPERLINK() occurs in the formula.
244 bool mbFromRangeName
:1; // If this array originates from a named expression
245 bool mbShareable
:1; // Whether or not it can be shared with adjacent cells.
246 bool mbFinalized
:1; // Whether code arrays have their final used size and no more tokens can be added.
249 void Assign( const FormulaTokenArray
& );
250 void Assign( sal_uInt16 nCode
, FormulaToken
**pTokens
);
252 /// Also used by the compiler. The token MUST had been allocated with new!
253 FormulaToken
* Add( FormulaToken
* );
258 CODE_ONLY
, ///< replacement only in pCode
259 CODE_AND_RPN
///< replacement in pCode and pRPN
262 /** Also used by the compiler. The token MUST had been allocated with new!
264 Absolute offset in pCode of the token to be replaced.
266 If CODE_ONLY only the token in pCode at nOffset is replaced.
267 If CODE_AND_RPN the token in pCode at nOffset is replaced;
268 if the original token was also referenced in the pRPN array
269 then that reference is replaced with a reference to the new
272 FormulaToken
* ReplaceToken( sal_uInt16 nOffset
, FormulaToken
*, ReplaceMode eMode
);
274 /** Remove a sequence of tokens from pCode array, and pRPN array if the
275 tokens are referenced there.
277 nLen and nRPN are adapted.
280 Start offset into pCode.
282 Count of tokens to remove.
284 @return Count of tokens removed.
286 sal_uInt16
RemoveToken( sal_uInt16 nOffset
, sal_uInt16 nCount
);
289 /** Assignment with incrementing references of FormulaToken entries
291 FormulaTokenArray( const FormulaTokenArray
& );
292 virtual ~FormulaTokenArray();
294 virtual void Clear();
297 * The array has its final used size and no more token can be added.
301 void SetFromRangeName( bool b
) { mbFromRangeName
= b
; }
302 bool IsFromRangeName() const { return mbFromRangeName
; }
304 void SetShareable( bool b
) { mbShareable
= b
; }
307 * Check if this token array is shareable between multiple adjacent
308 * formula cells. Certain tokens may not function correctly when shared.
310 * @return true if the token array is shareable, false otherwise.
312 bool IsShareable() const { return mbShareable
; }
315 FormulaToken
* FirstToken() const;
317 /// Return pCode[nIdx], or nullptr if nIdx is out of bounds
318 FormulaToken
* TokenAt( sal_uInt16 nIdx
) const
325 /// Peek at nIdx-1 if not out of bounds, decrements nIdx if successful. Returns NULL if not.
326 FormulaToken
* PeekPrev( sal_uInt16
& nIdx
) const;
328 /// Return the opcode at pCode[nIdx-1], ocNone if nIdx-1 is out of bounds
329 OpCode
OpCodeBefore( sal_uInt16 nIdx
) const
331 if (nIdx
== 0 || nIdx
> nLen
)
334 return pCode
[nIdx
-1]->GetOpCode();
337 FormulaToken
* FirstRPNToken() const;
339 bool HasReferences() const;
341 bool HasExternalRef() const;
342 bool HasOpCode( OpCode
) const;
343 bool HasOpCodeRPN( OpCode
) const;
344 /// Token of type svIndex or opcode ocColRowName
345 bool HasNameOrColRowName() const;
348 * Check if the token array contains any of specified opcode tokens.
350 * @param rOpCodes collection of opcodes to check against.
352 * @return true if the token array contains at least one of the specified
353 * opcode tokens, false otherwise.
355 bool HasOpCodes( const unordered_opcode_set
& rOpCodes
) const;
357 /// Assign pRPN to point to a newly created array filled with the data from pData
358 void CreateNewRPNArrayFromData( FormulaToken
** pData
, sal_uInt16 nSize
)
360 pRPN
= new FormulaToken
*[ nSize
];
362 memcpy( pRPN
, pData
, nSize
* sizeof( FormulaToken
* ) );
365 FormulaToken
** GetArray() const { return pCode
.get(); }
367 FormulaTokenArrayStandardRange
Tokens() const
369 return FormulaTokenArrayStandardRange(pCode
.get(), nLen
);
372 FormulaToken
** GetCode() const { return pRPN
; }
374 FormulaTokenArrayStandardRange
RPNTokens() const
376 return FormulaTokenArrayStandardRange(pRPN
, nRPN
);
379 FormulaTokenArrayReferencesRange
References() const
381 return FormulaTokenArrayReferencesRange(*this);
384 sal_uInt16
GetLen() const { return nLen
; }
385 sal_uInt16
GetCodeLen() const { return nRPN
; }
386 FormulaError
GetCodeError() const { return nError
; }
387 void SetCodeError( FormulaError n
) { nError
= n
; }
388 void SetHyperLink( bool bVal
) { bHyperLink
= bVal
; }
389 bool IsHyperLink() const { return bHyperLink
; }
391 ScRecalcMode
GetRecalcMode() const { return nMode
; }
393 void SetCombinedBitsRecalcMode( ScRecalcMode nBits
)
394 { nMode
|= nBits
& ~ScRecalcMode::EMask
; }
395 ScRecalcMode
GetCombinedBitsRecalcMode() const
396 { return nMode
& ~ScRecalcMode::EMask
; }
398 /** Exclusive bits already set in nMode are zero'ed, nBits
399 may contain combined bits, but only one exclusive bit
401 void SetMaskedRecalcMode( ScRecalcMode nBits
)
402 { nMode
= GetCombinedBitsRecalcMode() | nBits
; }
404 /** Bits aren't set directly but validated and handled
405 according to priority if more than one exclusive bit
407 void AddRecalcMode( ScRecalcMode nBits
);
409 void ClearRecalcMode() { nMode
= ScRecalcMode::NORMAL
; }
410 void SetExclusiveRecalcModeNormal()
411 { SetMaskedRecalcMode( ScRecalcMode::NORMAL
); }
412 void SetExclusiveRecalcModeAlways()
413 { SetMaskedRecalcMode( ScRecalcMode::ALWAYS
); }
414 void SetRecalcModeForced()
415 { nMode
|= ScRecalcMode::FORCED
; }
416 void SetRecalcModeOnRefMove()
417 { nMode
|= ScRecalcMode::ONREFMOVE
; }
418 bool IsRecalcModeNormal() const
419 { return bool(nMode
& ScRecalcMode::NORMAL
); }
420 bool IsRecalcModeAlways() const
421 { return bool(nMode
& ScRecalcMode::ALWAYS
); }
422 bool IsRecalcModeForced() const
423 { return bool(nMode
& ScRecalcMode::FORCED
); }
424 bool IsRecalcModeOnRefMove() const
425 { return bool(nMode
& ScRecalcMode::ONREFMOVE
); }
426 /** Whether recalculation must happen after import, for
428 bool IsRecalcModeMustAfterImport() const
429 { return (nMode
& ScRecalcMode::EMask
) <= ScRecalcMode::ONLOAD_ONCE
; }
431 /** Get OpCode of the most outer function */
432 inline OpCode
GetOuterFuncOpCode() const;
434 /** Operators +,-,*,/,^,&,=,<>,<,>,<=,>=
435 with DoubleRef in Formula? */
436 bool HasMatrixDoubleRefOps() const;
438 virtual FormulaToken
* AddOpCode(OpCode e
);
440 /** Adds the single token to array.
441 Derived classes must override it when they want to support derived classes from FormulaToken.
442 @return true when an error occurs
444 virtual bool AddFormulaToken(
445 const css::sheet::FormulaToken
& rToken
, svl::SharedStringPool
& rSPool
,
446 ExternalReferenceHelper
* pExtRef
);
448 /** fill the array with the tokens from the sequence.
449 It calls AddFormulaToken for each token in the list.
450 @param _aSequence the token to add
451 @return true when an error occurs
454 const css::uno::Sequence
<css::sheet::FormulaToken
>& rSequence
,
455 svl::SharedStringPool
& rSPool
, ExternalReferenceHelper
* pExtRef
);
458 * Do some checking based on the individual tokens. For now, we use this
459 * only to check whether we can vectorize the token array.
461 virtual void CheckToken( const FormulaToken
& t
);
464 * Call CheckToken() for all RPN tokens.
466 void CheckAllRPNTokens();
468 /** Clones the token and then adds the clone to the pCode array.
469 For just new'ed tokens use Add() instead of cloning it again.
470 Use this AddToken() when adding a token from another origin.
472 FormulaToken
* AddToken( const FormulaToken
& );
474 FormulaToken
* AddString( const svl::SharedString
& rStr
);
475 FormulaToken
* AddDouble( double fVal
);
476 void AddExternal( const sal_Unicode
* pStr
);
477 /** Xcl import may play dirty tricks with OpCode!=ocExternal.
479 FormulaToken
* AddExternal( const OUString
& rStr
, OpCode eOp
= ocExternal
);
480 FormulaToken
* AddBad( const OUString
& rStr
); /// ocBad with OUString
481 FormulaToken
* AddStringXML( const OUString
& rStr
); /// ocStringXML with OUString, temporary during import
483 virtual FormulaToken
* MergeArray( );
485 /** Assignment with incrementing references of FormulaToken entries
487 FormulaTokenArray
& operator=( const FormulaTokenArray
& );
489 /** Determines if this formula needs any changes to convert it to something
490 previous versions of OOo could consume (Plain Old Formula, pre-ODFF, or
492 bool NeedsPodfRewrite( const MissingConventionODF
& rConv
);
494 /** Determines if this formula needs any changes to convert it to OOXML. */
495 bool NeedsOoxmlRewrite();
497 /** Rewrites to Plain Old Formula or OOXML, substituting missing parameters. The
498 FormulaTokenArray* returned is new'ed. */
499 FormulaTokenArray
* RewriteMissing( const MissingConvention
& rConv
);
501 /** Determines if this formula may be followed by a reference. */
502 bool MayReferenceFollow();
504 /** Re-intern SharedString in case the SharedStringPool differs. */
505 void ReinternStrings( svl::SharedStringPool
& rPool
);
508 inline OpCode
FormulaTokenArray::GetOuterFuncOpCode() const
511 return pRPN
[nRPN
-1]->GetOpCode();
515 inline FormulaTokenArrayReferencesIterator
FormulaTokenArrayReferencesRange::begin()
517 return FormulaTokenArrayReferencesIterator(mrFTA
.Tokens());
520 inline FormulaTokenArrayReferencesIterator
FormulaTokenArrayReferencesRange::end()
522 return FormulaTokenArrayReferencesIterator::endOf(mrFTA
.Tokens());
525 class FORMULA_DLLPUBLIC FormulaTokenIterator
530 const FormulaTokenArray
* pArr
;
534 Item(const FormulaTokenArray
* arr
, short pc
, short stop
);
537 std::vector
<Item
> maStack
;
540 FormulaTokenIterator( const FormulaTokenArray
& );
541 ~FormulaTokenIterator();
543 const FormulaToken
* Next();
544 const FormulaToken
* PeekNextOperator();
545 bool IsEndOfPath() const; /// if a jump or subroutine path is done
546 bool HasStacked() const { return maStack
.size() > 1; }
547 short GetPC() const { return maStack
.back().nPC
; }
549 /** Jump or subroutine call.
550 Program counter values will be incremented before code is executed =>
551 positions are to be passed with -1 offset.
553 Start on code at position nStart+1 (yes, pass with offset -1)
555 After subroutine continue with instruction at position nNext+1
557 Stop before reaching code at position nStop. If not specified the
558 default is to either run the entire code, or to stop if an ocSep or
559 ocClose is encountered, which are only present in ocIf or ocChoose
562 void Jump( short nStart
, short nNext
, short nStop
= SHRT_MAX
);
563 void Push( const FormulaTokenArray
* );
566 /** Reconstruct the iterator afresh from a token array
568 void ReInit( const FormulaTokenArray
& );
571 const FormulaToken
* GetNonEndOfPathToken( short nIdx
) const;
574 // For use in SAL_INFO, SAL_WARN etc
576 template<typename charT
, typename traits
>
577 inline std::basic_ostream
<charT
, traits
> & operator <<(std::basic_ostream
<charT
, traits
> & stream
, const FormulaTokenArray
& point
)
580 static_cast<const void*>(&point
) <<
581 ":{nLen=" << point
.GetLen() <<
582 ",nRPN=" << point
.GetCodeLen() <<
583 ",pCode=" << static_cast<void*>(point
.GetArray()) <<
584 ",pRPN=" << static_cast<void*>(point
.GetCode()) <<
590 class FORMULA_DLLPUBLIC FormulaTokenArrayPlainIterator
593 const FormulaTokenArray
* mpFTA
;
594 sal_uInt16 mnIndex
; // Current step index
597 FormulaTokenArrayPlainIterator( const FormulaTokenArray
& rFTA
) :
608 sal_uInt16
GetIndex() const
613 FormulaToken
* First()
619 void Jump(sal_uInt16 nIndex
)
630 FormulaToken
* Next();
631 FormulaToken
* NextNoSpaces();
632 FormulaToken
* GetNextName();
633 FormulaToken
* GetNextReference();
634 FormulaToken
* GetNextReferenceRPN();
635 FormulaToken
* GetNextReferenceOrName();
636 FormulaToken
* GetNextColRowName();
637 FormulaToken
* PeekNext();
638 FormulaToken
* PeekPrevNoSpaces() const; /// Only after Reset/First/Next/Last/Prev!
639 FormulaToken
* PeekNextNoSpaces() const; /// Only after Reset/First/Next/Last/Prev!
641 FormulaToken
* FirstRPN()
647 FormulaToken
* NextRPN();
649 FormulaToken
* LastRPN()
651 mnIndex
= mpFTA
->GetCodeLen();
655 FormulaToken
* PrevRPN();
657 void AfterRemoveToken( sal_uInt16 nOffset
, sal_uInt16 nCount
);
663 #endif // INCLUDED_FORMULA_TOKENARRAY_HXX
665 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */