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 #include "tokenuno.hxx"
22 #include <sal/macros.h>
24 #include <com/sun/star/sheet/ComplexReference.hpp>
25 #include <com/sun/star/sheet/ExternalReference.hpp>
26 #include <com/sun/star/sheet/ReferenceFlags.hpp>
27 #include <com/sun/star/sheet/AddressConvention.hpp>
28 #include <com/sun/star/sheet/NameToken.hpp>
29 #include <com/sun/star/table/CellAddress.hpp>
31 #include <svl/itemprop.hxx>
32 #include <vcl/svapp.hxx>
34 #include "miscuno.hxx"
35 #include "convuno.hxx"
36 #include "unonames.hxx"
38 #include "compiler.hxx"
39 #include "tokenarray.hxx"
41 #include "rangeseq.hxx"
42 #include "externalrefmgr.hxx"
44 using namespace ::formula
;
45 using namespace ::com::sun::star
;
47 static const SfxItemPropertyMapEntry
* lcl_GetFormulaParserMap()
49 static const SfxItemPropertyMapEntry aFormulaParserMap_Impl
[] =
51 {OUString(SC_UNO_COMPILEFAP
), 0, cppu::UnoType
<bool>::get(), 0, 0 },
52 {OUString(SC_UNO_COMPILEENGLISH
), 0, cppu::UnoType
<bool>::get(), 0, 0 },
53 {OUString(SC_UNO_IGNORELEADING
), 0, cppu::UnoType
<bool>::get(), 0, 0 },
54 {OUString(SC_UNO_FORMULACONVENTION
), 0, cppu::UnoType
<decltype(sheet::AddressConvention::UNSPECIFIED
)>::get(), 0, 0 },
55 {OUString(SC_UNO_OPCODEMAP
), 0, cppu::UnoType
<uno::Sequence
< sheet::FormulaOpCodeMapEntry
>>::get(), 0, 0 },
56 { OUString(), 0, css::uno::Type(), 0, 0 }
58 return aFormulaParserMap_Impl
;
61 SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj
, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS
)
63 ScFormulaParserObj::ScFormulaParserObj(ScDocShell
* pDocSh
) :
65 mnConv( sheet::AddressConvention::UNSPECIFIED
),
67 mbIgnoreSpaces( true ),
70 mpDocShell
->GetDocument().AddUnoObject(*this);
73 ScFormulaParserObj::~ScFormulaParserObj()
78 mpDocShell
->GetDocument().RemoveUnoObject(*this);
81 void ScFormulaParserObj::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
83 const SfxSimpleHint
* pSimpleHint
= dynamic_cast<const SfxSimpleHint
*>(&rHint
);
84 if ( pSimpleHint
&& pSimpleHint
->GetId() == SFX_HINT_DYING
)
90 void ScFormulaParserObj::SetCompilerFlags( ScCompiler
& rCompiler
) const
92 static const formula::FormulaGrammar::AddressConvention aConvMap
[] = {
93 formula::FormulaGrammar::CONV_OOO
, // <- AddressConvention::OOO
94 formula::FormulaGrammar::CONV_XL_A1
, // <- AddressConvention::XL_A1
95 formula::FormulaGrammar::CONV_XL_R1C1
, // <- AddressConvention::XL_R1C1
96 formula::FormulaGrammar::CONV_XL_OOX
, // <- AddressConvention::XL_OOX
97 formula::FormulaGrammar::CONV_LOTUS_A1
// <- AddressConvention::LOTUS_A1
99 static const sal_Int16 nConvMapCount
= sizeof(aConvMap
)/sizeof(aConvMap
[0]);
101 // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
102 // don't need to initialize things twice.
103 if (mxOpCodeMap
.get())
104 rCompiler
.SetFormulaLanguage( mxOpCodeMap
);
107 sal_Int32 nFormulaLanguage
= mbEnglish
?
108 sheet::FormulaLanguage::ENGLISH
:
109 sheet::FormulaLanguage::NATIVE
;
110 ScCompiler::OpCodeMapPtr xMap
= rCompiler
.GetOpCodeMap( nFormulaLanguage
);
111 rCompiler
.SetFormulaLanguage( xMap
);
114 formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_UNSPECIFIED
;
115 if (mnConv
>= 0 && mnConv
< nConvMapCount
)
116 eConv
= aConvMap
[mnConv
];
118 rCompiler
.SetRefConvention( eConv
);
119 rCompiler
.EnableJumpCommandReorder(!mbCompileFAP
);
120 rCompiler
.EnableStopOnError(!mbCompileFAP
);
122 rCompiler
.SetExternalLinks( maExternalLinks
);
125 uno::Sequence
<sheet::FormulaToken
> SAL_CALL
ScFormulaParserObj::parseFormula(
126 const OUString
& aFormula
, const table::CellAddress
& rReferencePos
)
127 throw (uno::RuntimeException
, std::exception
)
129 SolarMutexGuard aGuard
;
130 uno::Sequence
<sheet::FormulaToken
> aRet
;
134 ScDocument
& rDoc
= mpDocShell
->GetDocument();
135 ScExternalRefManager::ApiGuard
aExtRefGuard(&rDoc
);
137 ScAddress
aRefPos( ScAddress::UNINITIALIZED
);
138 ScUnoConversion::FillScAddress( aRefPos
, rReferencePos
);
139 ScCompiler
aCompiler( &rDoc
, aRefPos
);
140 aCompiler
.SetGrammar(rDoc
.GetGrammar());
141 SetCompilerFlags( aCompiler
);
143 ScTokenArray
* pCode
= aCompiler
.CompileString( aFormula
);
144 (void)ScTokenConversion::ConvertToTokenSequence( rDoc
, aRet
, *pCode
);
151 OUString SAL_CALL
ScFormulaParserObj::printFormula(
152 const uno::Sequence
<sheet::FormulaToken
>& aTokens
, const table::CellAddress
& rReferencePos
)
153 throw (uno::RuntimeException
, std::exception
)
155 SolarMutexGuard aGuard
;
160 ScDocument
& rDoc
= mpDocShell
->GetDocument();
162 (void)ScTokenConversion::ConvertToTokenArray( rDoc
, aCode
, aTokens
);
163 ScAddress
aRefPos( ScAddress::UNINITIALIZED
);
164 ScUnoConversion::FillScAddress( aRefPos
, rReferencePos
);
165 ScCompiler
aCompiler( &rDoc
, aRefPos
, aCode
);
166 aCompiler
.SetGrammar(rDoc
.GetGrammar());
167 SetCompilerFlags( aCompiler
);
169 OUStringBuffer aBuffer
;
170 aCompiler
.CreateStringFromTokenArray( aBuffer
);
171 aRet
= aBuffer
.makeStringAndClear();
179 uno::Reference
<beans::XPropertySetInfo
> SAL_CALL
ScFormulaParserObj::getPropertySetInfo()
180 throw(uno::RuntimeException
, std::exception
)
182 SolarMutexGuard aGuard
;
183 static uno::Reference
< beans::XPropertySetInfo
> aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
187 void SAL_CALL
ScFormulaParserObj::setPropertyValue(
188 const OUString
& aPropertyName
, const uno::Any
& aValue
)
189 throw(beans::UnknownPropertyException
, beans::PropertyVetoException
,
190 lang::IllegalArgumentException
, lang::WrappedTargetException
,
191 uno::RuntimeException
, std::exception
)
193 SolarMutexGuard aGuard
;
194 OUString
aString(aPropertyName
);
195 if ( aString
== SC_UNO_COMPILEFAP
)
197 aValue
>>= mbCompileFAP
;
199 else if ( aString
== SC_UNO_COMPILEENGLISH
)
201 bool bOldEnglish
= mbEnglish
;
202 if (aValue
>>= mbEnglish
)
204 // Need to recreate the symbol map to change English property
205 // because the map is const. So for performance reasons set
206 // CompileEnglish _before_ OpCodeMap!
207 if (mxOpCodeMap
.get() && mbEnglish
!= bOldEnglish
)
209 ScDocument
& rDoc
= mpDocShell
->GetDocument();
210 ScCompiler
aCompiler( &rDoc
, ScAddress());
211 aCompiler
.SetGrammar(rDoc
.GetGrammar());
212 mxOpCodeMap
= formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping
, mbEnglish
);
216 throw lang::IllegalArgumentException();
218 else if ( aString
== SC_UNO_FORMULACONVENTION
)
222 else if ( aString
== SC_UNO_IGNORELEADING
)
224 aValue
>>= mbIgnoreSpaces
;
226 else if ( aString
== SC_UNO_OPCODEMAP
)
228 if (aValue
>>= maOpCodeMapping
)
230 ScDocument
& rDoc
= mpDocShell
->GetDocument();
231 ScCompiler
aCompiler( &rDoc
, ScAddress());
232 aCompiler
.SetGrammar(rDoc
.GetGrammar());
233 mxOpCodeMap
= formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping
, mbEnglish
);
236 throw lang::IllegalArgumentException();
238 else if ( aString
== SC_UNO_EXTERNALLINKS
)
240 if (!(aValue
>>= maExternalLinks
))
241 throw lang::IllegalArgumentException();
244 throw beans::UnknownPropertyException();
247 uno::Any SAL_CALL
ScFormulaParserObj::getPropertyValue( const OUString
& aPropertyName
)
248 throw(beans::UnknownPropertyException
, lang::WrappedTargetException
,
249 uno::RuntimeException
, std::exception
)
251 SolarMutexGuard aGuard
;
253 OUString
aString(aPropertyName
);
254 if ( aString
== SC_UNO_COMPILEFAP
)
256 aRet
<<= mbCompileFAP
;
258 else if ( aString
== SC_UNO_COMPILEENGLISH
)
262 else if ( aString
== SC_UNO_FORMULACONVENTION
)
266 else if ( aString
== SC_UNO_IGNORELEADING
)
268 aRet
<<= mbIgnoreSpaces
;
270 else if ( aString
== SC_UNO_OPCODEMAP
)
272 aRet
<<= maOpCodeMapping
;
274 else if ( aString
== SC_UNO_EXTERNALLINKS
)
276 aRet
<<= maExternalLinks
;
279 throw beans::UnknownPropertyException();
283 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj
)
285 static void lcl_ExternalRefToApi( sheet::SingleReference
& rAPI
, const ScSingleRefData
& rRef
)
290 rAPI
.RelativeColumn
= 0;
291 rAPI
.RelativeRow
= 0;
292 rAPI
.RelativeSheet
= 0;
294 sal_Int32 nFlags
= 0;
295 if ( rRef
.IsColRel() )
297 nFlags
|= sheet::ReferenceFlags::COLUMN_RELATIVE
;
298 rAPI
.RelativeColumn
= rRef
.Col();
301 rAPI
.Column
= rRef
.Col();
303 if ( rRef
.IsRowRel() )
305 nFlags
|= sheet::ReferenceFlags::ROW_RELATIVE
;
306 rAPI
.RelativeRow
= rRef
.Row();
309 rAPI
.Row
= rRef
.Row();
311 if ( rRef
.IsColDeleted() ) nFlags
|= sheet::ReferenceFlags::COLUMN_DELETED
;
312 if ( rRef
.IsRowDeleted() ) nFlags
|= sheet::ReferenceFlags::ROW_DELETED
;
313 if ( rRef
.IsFlag3D() ) nFlags
|= sheet::ReferenceFlags::SHEET_3D
;
314 if ( rRef
.IsRelName() ) nFlags
|= sheet::ReferenceFlags::RELATIVE_NAME
;
318 static void lcl_SingleRefToApi( sheet::SingleReference
& rAPI
, const ScSingleRefData
& rRef
)
320 sal_Int32 nFlags
= 0;
321 if ( rRef
.IsColRel() )
323 nFlags
|= sheet::ReferenceFlags::COLUMN_RELATIVE
;
324 rAPI
.RelativeColumn
= rRef
.Col();
329 rAPI
.RelativeColumn
= 0;
330 rAPI
.Column
= rRef
.Col();
333 if ( rRef
.IsRowRel() )
335 nFlags
|= sheet::ReferenceFlags::ROW_RELATIVE
;
336 rAPI
.RelativeRow
= rRef
.Row();
341 rAPI
.RelativeRow
= 0;
342 rAPI
.Row
= rRef
.Row();
345 if ( rRef
.IsTabRel() )
347 nFlags
|= sheet::ReferenceFlags::SHEET_RELATIVE
;
348 rAPI
.RelativeSheet
= rRef
.Tab();
353 rAPI
.RelativeSheet
= 0;
354 rAPI
.Sheet
= rRef
.Tab();
357 if ( rRef
.IsColDeleted() ) nFlags
|= sheet::ReferenceFlags::COLUMN_DELETED
;
358 if ( rRef
.IsRowDeleted() ) nFlags
|= sheet::ReferenceFlags::ROW_DELETED
;
359 if ( rRef
.IsTabDeleted() ) nFlags
|= sheet::ReferenceFlags::SHEET_DELETED
;
360 if ( rRef
.IsFlag3D() ) nFlags
|= sheet::ReferenceFlags::SHEET_3D
;
361 if ( rRef
.IsRelName() ) nFlags
|= sheet::ReferenceFlags::RELATIVE_NAME
;
365 bool ScTokenConversion::ConvertToTokenArray( ScDocument
& rDoc
,
366 ScTokenArray
& rTokenArray
, const uno::Sequence
<sheet::FormulaToken
>& rSequence
)
368 return !rTokenArray
.Fill(rSequence
, rDoc
.GetSharedStringPool(), rDoc
.GetExternalRefManager());
371 bool ScTokenConversion::ConvertToTokenSequence( const ScDocument
& rDoc
,
372 uno::Sequence
<sheet::FormulaToken
>& rSequence
, const ScTokenArray
& rTokenArray
)
376 sal_Int32 nLen
= static_cast<sal_Int32
>(rTokenArray
.GetLen());
377 formula::FormulaToken
** pTokens
= rTokenArray
.GetArray();
380 rSequence
.realloc(nLen
);
381 for (sal_Int32 nPos
=0; nPos
<nLen
; nPos
++)
383 const formula::FormulaToken
& rToken
= *pTokens
[nPos
];
384 sheet::FormulaToken
& rAPI
= rSequence
[nPos
];
386 OpCode eOpCode
= rToken
.GetOpCode();
387 // eOpCode may be changed in the following switch/case
388 switch ( rToken
.GetType() )
391 // Only the count of spaces is stored as "long". Parameter count is ignored.
392 if ( eOpCode
== ocSpaces
)
393 rAPI
.Data
<<= (sal_Int32
) rToken
.GetByte();
395 rAPI
.Data
.clear(); // no data
397 case formula::svDouble
:
398 rAPI
.Data
<<= rToken
.GetDouble();
400 case formula::svString
:
401 rAPI
.Data
<<= rToken
.GetString().getString();
404 // Function name is stored as string.
405 // Byte (parameter count) is ignored.
406 rAPI
.Data
<<= OUString( rToken
.GetExternal() );
410 sheet::SingleReference aSingleRef
;
411 lcl_SingleRefToApi( aSingleRef
, *rToken
.GetSingleRef() );
412 rAPI
.Data
<<= aSingleRef
;
415 case formula::svDoubleRef
:
417 sheet::ComplexReference aCompRef
;
418 lcl_SingleRefToApi( aCompRef
.Reference1
, *rToken
.GetSingleRef() );
419 lcl_SingleRefToApi( aCompRef
.Reference2
, *rToken
.GetSingleRef2() );
420 rAPI
.Data
<<= aCompRef
;
425 sheet::NameToken aNameToken
;
426 aNameToken
.Index
= static_cast<sal_Int32
>( rToken
.GetIndex() );
427 aNameToken
.Global
= rToken
.IsGlobal();
428 rAPI
.Data
<<= aNameToken
;
432 if (!ScRangeToSequence::FillMixedArray( rAPI
.Data
, rToken
.GetMatrix(), true))
435 case svExternalSingleRef
:
437 sheet::SingleReference aSingleRef
;
438 lcl_ExternalRefToApi( aSingleRef
, *rToken
.GetSingleRef() );
440 rDoc
.GetExternalRefManager()->getCacheTable(
441 rToken
.GetIndex(), rToken
.GetString().getString(), false, &nCacheId
);
442 aSingleRef
.Sheet
= static_cast< sal_Int32
>( nCacheId
);
443 sheet::ExternalReference aExtRef
;
444 aExtRef
.Index
= rToken
.GetIndex();
445 aExtRef
.Reference
<<= aSingleRef
;
446 rAPI
.Data
<<= aExtRef
;
450 case svExternalDoubleRef
:
452 sheet::ComplexReference aComplRef
;
453 lcl_ExternalRefToApi( aComplRef
.Reference1
, *rToken
.GetSingleRef() );
454 lcl_ExternalRefToApi( aComplRef
.Reference2
, *rToken
.GetSingleRef2() );
456 rDoc
.GetExternalRefManager()->getCacheTable(
457 rToken
.GetIndex(), rToken
.GetString().getString(), false, &nCacheId
);
458 aComplRef
.Reference1
.Sheet
= static_cast< sal_Int32
>( nCacheId
);
459 // NOTE: This assumes that cached sheets are in consecutive order!
460 aComplRef
.Reference2
.Sheet
=
461 aComplRef
.Reference1
.Sheet
+
462 (rToken
.GetSingleRef2()->Tab() - rToken
.GetSingleRef()->Tab());
463 sheet::ExternalReference aExtRef
;
464 aExtRef
.Index
= rToken
.GetIndex();
465 aExtRef
.Reference
<<= aComplRef
;
466 rAPI
.Data
<<= aExtRef
;
472 sheet::ExternalReference aExtRef
;
473 aExtRef
.Index
= rToken
.GetIndex();
474 aExtRef
.Reference
<<= rToken
.GetString().getString();
475 rAPI
.Data
<<= aExtRef
;
480 OSL_TRACE( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken
.GetType());
482 case svSep
: // occurs with ocSep, ocOpen, ocClose, ocArray*
483 case svJump
: // occurs with ocIf, ocChoose
484 case svMissing
: // occurs with ocMissing
485 rAPI
.Data
.clear(); // no data
487 rAPI
.OpCode
= static_cast<sal_Int32
>(eOpCode
); //! assuming equal values for the moment
491 rSequence
.realloc(0);
496 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::unique_ptr
<formula::FormulaCompiler
> && _pCompiler
)
497 : formula::FormulaOpCodeMapperObj(std::move(_pCompiler
))
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */