ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
compiler.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2024 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
7
9
10#if !DOXYGEN
20# if ALIB_CAMP
22# endif
24#endif // !DOXYGEN
25
26namespace alib { namespace expressions {
27
28using namespace detail;
29
30// #################################################################################################
31// Scope constructor, Clear()
32// #################################################################################################
33Scope::Scope( SPFormatter& formatter) // evaluation scope constructor using an own allocator
34: evalScopeAllocator(MonoAllocator::Create(ALIB_DBG("ExpressionScope",) 1, 200))
35, Allocator (*evalScopeAllocator)
36, Stack (Allocator().New<StdVectorMono<Box>>(Allocator))
37, Formatter (formatter)
38, vmMembers (Allocator().New<VMMembers>(Allocator))
39, NamedResources (nullptr)
41, dcs ("ExpressionEvalScope")
42#endif
43{}
44
45Scope::Scope( MonoAllocator& allocator, SPFormatter& formatter )
46: evalScopeAllocator(nullptr) // compile-time scope constructor using the allocator of the expression
47, Allocator (allocator)
48, Stack (Allocator().New<StdVectorMono<Box>>(Allocator))
49, Formatter (formatter)
50, vmMembers (nullptr)
51, NamedResources (Allocator().New< HashMap< MonoAllocator,
52 NString,
53 ScopeResource* > >(Allocator) )
55, dcs ("ExpressionCTScope")
56#endif
57{}
58
59Scope::~Scope()
60{
61 // Destruct members in vectors and tables.
65 {
68 }
69}
70
71
72void Scope::freeResources()
73{
74 Stack->clear();
75
76 if ( NamedResources )
77 for( auto resource : *NamedResources )
78 lang::Destruct(*resource.second);
79}
80
81void Scope::reset()
82{
84
85 // save sizes
86 auto stackSize= Stack->size();
87 auto nestedExpressionsSize= vmMembers->NestedExpressions.size();
88
89 // free and destruct
93 Allocator.Reset(sizeof(MonoAllocator), alignof(MonoAllocator));
94
95 // create new
98
99 // reserve storage of the previous sizes for the next run.
100 Stack->reserve( stackSize );
101 vmMembers->NestedExpressions.reserve(nestedExpressionsSize );
102}
103
104
105// #################################################################################################
106// Constructor & Setup
107// #################################################################################################
109: allocator (ALIB_DBG("ExpressionCompiler",) 4)
110, typeMap (allocator, 2.0, 5.0) // we don't care about speed here, just for log output
111, namedExpressions (allocator)
112, UnaryOperators (allocator)
113, AlphabeticUnaryOperatorAliases (allocator)
114, AlphabeticBinaryOperatorAliases(allocator)
115, BinaryOperators (allocator)
116, CfgNormalizationDisallowed (allocator)
117{
118 // create a clone of the default formatter.
120
121 // register compiler types
123 constexpr std::pair<Box&,NString> typeKeys[]=
124 {
125 { Types::Void , "T_VOID" },
126 { Types::Boolean , "T_BOOL" },
127 { Types::Integer , "T_INT" },
128 { Types::Float , "T_FLOAT" },
129 { Types::String , "T_STR" },
131 { Types::DateTime , "T_DATE" },
132 { Types::Duration , "T_DUR" }, )
133 };
135
136 size_t idx= sizeof( typeKeys ) / sizeof( std::pair<Box&, NString> );
137 do
138 {
139 --idx;
140 auto& name= EXPRESSIONS.GetResource( typeKeys[idx].second );
141 ALIB_STRINGS_TO_NARROW( name, nameNarrow, 128 )
142 AddType( typeKeys[idx].first, nameNarrow );
143 }
144 while( idx != 0 );
145
146 // load nested expression function descriptor
149}
150
152{
153 if( Repository != nullptr )
154 delete Repository;
155}
156
158{
159 auto* result= ctAllocator().New<Scope>( ctAllocator, CfgFormatter );
160 return result;
161}
162
164{
165 //------------- add default unary ops ----------
167 {
169 ALIB_ASSERT_ERROR( enumRecordIt.Enum() == DefaultUnaryOperators::NONE, "EXPR",
170 "Expected none-operator as first enum record" )
171 while( ++enumRecordIt != EnumRecords<DefaultUnaryOperators>::end() )
172 AddUnaryOperator( enumRecordIt->EnumElementName );
173
174 // default unary op aliases
176 {
177 // Not -> !
179 if( record.Symbol.IsNotEmpty() )
180 AlphabeticUnaryOperatorAliases.EmplaceOrAssign( record.Symbol,
181 record.Replacement );
182 }
183 }
184
185 //------------- add default binary ops ----------
187 {
189 ALIB_ASSERT_ERROR( enumRecordIt.Enum() == DefaultBinaryOperators::NONE, "EXPR",
190 "Expected none-operator as first enum record" )
191 while( ++enumRecordIt != EnumRecords<DefaultBinaryOperators>::end() ) {
192 // get symbol
193 if ( enumRecordIt->Symbol.Equals<NC>(A_CHAR("[]"))
195 continue;
196
197 // use equal operator's precedence for assign operator, if aliased.
198 auto precedence = ( enumRecordIt.Enum() == DefaultBinaryOperators::Assign
199 && HasBits(CfgCompilation,
202 : enumRecordIt->Precedence;
203
204 AddBinaryOperator(enumRecordIt->Symbol, precedence);
205 }
206
207 // default binary op aliases
210 AlphabeticBinaryOperatorAliases.EmplaceOrAssign( enumEntry.Symbol,
211 enumEntry.Replacement );
212 }
213
214
215 //------------- add default plug-ins ----------
216 CfgNormalizationDisallowed.emplace_back( A_CHAR("--") );
217 CfgNormalizationDisallowed.emplace_back( A_CHAR("++") );
218
221
224
227
230
233
235 if( HasBits( CfgBuiltInPlugins, BuiltInPlugins::DateAndTime ) )
237}
238
239// #############################################################################################
240// Parse and compile
241// #############################################################################################
242Expression Compiler::Compile( const String& expressionString )
243{
244 // checks
245 ALIB_ASSERT_ERROR( HasPlugins(), "EXPR",
246 "No plug-ins attached. Invoke SetupDefaults() on compiler instance." )
247 ALIB_ASSERT_ERROR( expressionString.IsNotNull(), "EXPR", "Nulled expression string." )
248 if( expressionString.IsEmpty() )
250
251
252 Expression expression( 1, 100 );
253 expression.ConstructT( expression.GetAllocator(),
254 expressionString,
255 createCompileTimeScope(expression.GetAllocator()) );
256
257 // parser
258 if (parser == nullptr)
259 parser= Parser::Create( *this );
260
261 AST* ast = nullptr;
262
263 // prevent cleaning memory with recursive compilation (may happen with nested expressions)
264 static integer recursionCounter= 0;
265 monomem::Snapshot startOfCompilation;
266 if( recursionCounter++ == 0 )
267 startOfCompilation= allocator.TakeSnapshot();
268
269 try
270 {
271 #if ALIB_TIME && ALIB_DEBUG
272 Ticks startTime;
273 #endif
274
275 // parse
276 ast= parser->Parse( expressionString, &CfgFormatter->DefaultNumberFormat );
277
278 #if ALIB_TIME && ALIB_DEBUG
279 expression->DbgParseTime= startTime.Age();
280 startTime= Ticks::Now();
281 #endif
282
283 // optimize on AST level
284 ast= ast->Optimize( CfgNormalization );
285
286 // create program
287 expression->program= new detail::Program( *this, *expression, &allocator );
288
289 // assemble
290 ast->Assemble( *expression->program, allocator, expression->normalizedString );
291 expression->normalizedString.TrimEnd();
292
293 expression->program->AssembleFinalize();
294 #if ALIB_TIME && ALIB_DEBUG
295 expression->DbgAssemblyTime= startTime.Age();
296 #endif
297
298 if(--recursionCounter == 0)
299 allocator.Reset( startOfCompilation );
300
301 // checks
302 ALIB_ASSERT_ERROR( !expression->program->ResultType().IsType<void>(), "EXPR",
303 "No exception when parsing expression, but result type is void!" )
304
305 ALIB_ASSERT_ERROR( !expression->program->ResultType().IsType<void>(), "EXPR",
306 "No exception when parsing expression, but result type is void." )
307 }
308 catch( Exception& )
309 {
310 expression= nullptr;
311 if(--recursionCounter == 0)
312 allocator.Reset( startOfCompilation );
313 throw;
314 }
315 catch( std::exception& )
316 {
317 expression= nullptr;
318 if(--recursionCounter == 0)
319 allocator.Reset( startOfCompilation );
320 throw;
321 }
322
323 // Assert that nobody touches this allocator from now on. With evaluations,
324 // exclusively the evaluation scope is to be used.
325 expression->ctScope->Allocator.DbgLock(true);
326
327 return Expression(expression);
328}
329
331{
332 detail::AST* ast= nullptr;
333 auto startOfDecompilation= allocator.TakeSnapshot();
334 try
335 {
336 expression.allocator.DbgLock(false);
337 ast = detail::VirtualMachine::Decompile( *dynamic_cast<Program*>(expression.program),
338 allocator );
339 detail::Program* program= allocator().New<detail::Program>( *this, expression, nullptr );
340 ast->Assemble( *program, allocator, expression.optimizedString );
341 program->AssembleFinalize();
342 lang::Destruct(*program);
343 expression.allocator.DbgLock(true);
344 }
345 catch(Exception& )
346 {
347 allocator.Reset( startOfDecompilation );
348 throw;
349 }
350 allocator.Reset( startOfDecompilation );
351}
352
353
354// #############################################################################################
355// Manage named expressions
356// #############################################################################################
357
358bool Compiler::AddNamed( const String& name, const String& expressionString )
359{
360 String128 key;
362 key << name;
364 key.ToUpper();
365
366 auto it= namedExpressions.Find( key );
367 bool existed= it != namedExpressions.end();
368
369 // removal requested?
370 if( expressionString.IsNull() )
371 {
372 if ( existed )
373 {
374 namedExpressions.Erase( it );
375 return true;
376 }
377 return false;
378 }
379
380 auto compiledExpression= Compile( expressionString );
381 compiledExpression->allocator.DbgLock(false);
382 compiledExpression->name.Allocate( compiledExpression->allocator, name);
383 compiledExpression->allocator.DbgLock(true);
384 ALIB_ASSERT( compiledExpression )
385 if( existed )
386 it.Mapped()= compiledExpression;
387 else
388 namedExpressions.EmplaceUnique( key, compiledExpression );
389 return existed;
390}
391
393{
394 // search
395 String128 key;
397 key << name;
399 key.ToUpper();
400
401 auto it= namedExpressions.Find( key );
402 if( it != namedExpressions.end() )
403 return it.Mapped();
404
405 // not found! -> use protected, virtual method to get the string from somewhere
406 AString expressionString;
407 if (Repository == nullptr || !Repository->Get( name, expressionString ) )
409
410 // Got an expression string! -> Compile
411 Expression parsedExpression= Compile( expressionString );
412
413 parsedExpression->allocator.DbgLock(false);
414 parsedExpression->name.Allocate( parsedExpression->allocator, name );
415 parsedExpression->allocator.DbgLock(true);
416
417 Expression sharedExpression( parsedExpression );
418 namedExpressions.EmplaceUnique( key, sharedExpression );
419
420 return sharedExpression;
421}
422
423// #################################################################################################
424// Helpers
425// #################################################################################################
426void Compiler::AddType( Type sample, const NString& name )
427{
428 ALIB_DBG( auto it= )
429 typeMap.EmplaceIfNotExistent( &sample.TypeID(), name );
430 ALIB_ASSERT_ERROR( it.second == true, "EXPR", // is insert
431 "Type already registered with compiler." )
432}
433
435{
436 if( box.IsType<void>() )
437 return "NONE";
438
439 auto entry= typeMap.Find( &box.TypeID() );
440 ALIB_ASSERT_WARNING( entry != typeMap.end(), "EXPR",
441 "Custom type {!Q} not registered. Please use Compiler::AddType to do so.",
442 box.TypeID() )
443 if( entry == typeMap.end() )
444 return "Unknown Type";
445
446 return entry.Mapped();
447}
448
450void Compiler::WriteFunctionSignature( Box** boxArray, size_t qty, AString& target )
451{
452 bool variadic= qty && (*(boxArray + qty -1)) == nullptr;
453 if( variadic )
454 --qty;
455
456 target<< '(';
457 bool isFirst= true;
458 for( size_t i= 0 ; i < qty ; ++i )
459 {
460 if(!isFirst)
461 target<< ", ";
462 isFirst= false;
463 target << '<' << TypeName( **boxArray++ ) << '>';
464 }
465 if(variadic)
466 {
467 if(!isFirst)
468 target<< ", ";
469 target<< "...";
470 }
471
472 target<< ')';
473}
475
477 ArgIterator end,
478 AString& target )
479{
480 std::vector<Box*> buf;
481 buf.reserve( size_t(end - begin) );
482 while( begin != end )
483 buf.emplace_back( &*begin++ );
484 WriteFunctionSignature( buf.data(), buf.size(), target );
485}
486
487
488
489}} // namespace [alib::expressions]
bool IsType() const
const std::type_info & TypeID() const
Definition box.inl:941
void AddBinaryOperator(const String &symbol, int precedence)
Definition compiler.hpp:178
HashMap< MonoAllocator, String, String, alib::hash_string_ignore_case< character >, alib::equal_to_string_ignore_case< character > > AlphabeticUnaryOperatorAliases
Definition compiler.hpp:132
virtual ALIB_API Expression Compile(const String &expressionString)
Definition compiler.cpp:242
StringVectorMA CfgNormalizationDisallowed
Definition compiler.hpp:298
HashMap< MonoAllocator, String, String, alib::hash_string_ignore_case< character >, alib::equal_to_string_ignore_case< character > > AlphabeticBinaryOperatorAliases
Definition compiler.hpp:142
ALIB_API NString TypeName(Type box)
Definition compiler.cpp:434
ExpressionRepository * Repository
Definition compiler.hpp:322
HashMap< MonoAllocator, TypeFunctors::Key, NAString, TypeFunctors::Hash, TypeFunctors::EqualTo > typeMap
The map of Type names and bit flag values.
Definition compiler.hpp:96
ALIB_API void AddType(Type sample, const NString &name)
Definition compiler.cpp:426
ALIB_API void getOptimizedExpressionString(ExpressionVal &expression)
Definition compiler.cpp:330
HashMap< MonoAllocator, AString, Expression, std::hash< String >, std::equal_to< String > > namedExpressions
The map of 'named' expressions.
Definition compiler.hpp:102
Compilation CfgCompilation
Compilation flags.
Definition compiler.hpp:273
strings::util::Token CfgNestedExpressionFunction
Definition compiler.hpp:264
detail::Parser * parser
The expression parser.
Definition compiler.hpp:90
virtual ALIB_API bool AddNamed(const String &name, const String &expressionString)
Definition compiler.cpp:358
Normalization CfgNormalization
Definition compiler.hpp:277
ALIB_API void WriteFunctionSignature(Box **boxArray, size_t qty, AString &target)
Definition compiler.cpp:450
ALIB_API void SetupDefaults()
Definition compiler.cpp:163
virtual ALIB_API ~Compiler()
Destructor.
Definition compiler.cpp:151
@ AutoCast
Installs plugins::AutoCast.
@ IF_ALIB_CAMP
Installs plugins::DateAndTime. )
@ Arithmetics
Installs plugins::Arithmetics.
@ Strings
Installs plugins::Strings.
@ ElvisOperator
Installs plugins::ElvisOperator.
virtual ALIB_API Scope * createCompileTimeScope(MonoAllocator &expressionAllocator)
Definition compiler.cpp:157
BuiltInPlugins CfgBuiltInPlugins
Definition compiler.hpp:239
virtual ALIB_API Expression GetNamed(const String &name)
Definition compiler.cpp:392
void AddUnaryOperator(const String &symbol)
Definition compiler.hpp:150
virtual bool Get(const String &identifier, AString &target)=0
detail::Program * program
The compiled expression program.
const String & GetResource(const NString &name)
void InsertPlugin(CompilerPlugin *plugin, lang::Responsibility responsibility=lang::Responsibility::KeepWithSender)
static ALIB_API SPFormatter Default
virtual SPFormatter Clone()=0
ALIB_API void Reset(Snapshot snapshot=Snapshot())
ALIB_FORCE_INLINE void DbgLock(bool onOff) noexcept
AllocatorType & GetAllocator() noexcept
void ConstructT(TArgs &&... args)
TAString & ToUpper(integer regionStart=0, integer regionLength=MAX_LEN)
void DbgDisableBufferReplacementWarning()
Definition tastring.inl:363
constexpr bool IsNull() const
Definition string.hpp:364
constexpr bool IsEmpty() const
Definition string.hpp:383
constexpr bool IsNotNull() const
Definition string.hpp:371
static ALIB_API void LoadResourcedTokens(lang::resources::ResourcePool &resourcePool, const NString &resourceCategory, const NString &resourceName, strings::util::Token *target, int dbgSizeVerifier, character outerSeparator=',', character innerSeparator=' ')
#define ALIB_CALLER_NULLED
Definition alib.hpp:1173
#define ALIB_CALLER
Definition alib.hpp:1164
#define A_CHAR(STR)
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:849
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:1271
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:760
#define ALIB_ASSERT_WARNING(cond,...)
Definition alib.hpp:1272
#define ALIB_DBG(...)
Definition alib.hpp:390
#define ALIB_ASSERT(cond)
Definition alib.hpp:1270
#define ALIB_DEBUG_CRITICAL_SECTIONS
Definition prepro.md:44
const T_EnumRecords< TEnum >::Type & GetRecord(TEnum element)
StdVectorMono< Box >::iterator ArgIterator
@ Equal
Equal operator ('=='). Precedence 500.
@ NamedExpressionNotFound
Compile-time exception thrown when an expression refers to an unknown named nested expression.
@ EmptyExpressionString
Thrown when an empty string is tried to be compiled.
static ALIB_FORCE_INLINE void Destruct(T &object)
@ Transfer
Transfers responsibility to the receiving party.
Definition alib.cpp:69
lang::Exception Exception
Type alias in namespace alib.
expressions::ExpressionsCamp EXPRESSIONS
The singleton instance of ALib Camp class ExpressionsCamp.
std::vector< T, SCAMono< T > > StdVectorMono
Type alias in namespace alib.
Definition stdvector.hpp:21
expressions::Expression Expression
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:273
static ForwardIterator begin()
Definition records.hpp:413
Members used by the virtual machine. This is constructed only with evaluation-time scopes.
Definition scope.hpp:80
StdVectorMono< ExpressionVal * > NestedExpressions
Stack of nested expressions called during evaluation. Used to detect cyclic expressions.
Definition scope.hpp:99
HashMap< MonoAllocator, NString, ScopeResource * > * NamedResources
Definition scope.hpp:163
MonoAllocator * evalScopeAllocator
Definition scope.hpp:126
StdVectorMono< Box > * Stack
Definition scope.hpp:140
VMMembers * vmMembers
The members used for the virtual machine. Available only with evaluation-time instances.
Definition scope.hpp:157
virtual ALIB_API void freeResources()
This method is called in the destructor, as well as in method reset.
Definition compiler.cpp:72
MonoAllocator & Allocator
Definition scope.hpp:135
static ALIB_API Box DateTime
Sample type-box for date and time values of type DateTime).
static ALIB_API Box Duration
Sample type-box for values of type DateTime::Duration).
static ALIB_API Box Void
Sample type-box for C++ type void.
static ALIB_API Box Integer
Sample type-box for integer types. (Precisely for type integer.)
static ALIB_API Box Boolean
Sample type-box for C++ type bool.
static ALIB_API Box String
static ALIB_API Box Float
Sample type-box for C++ type double.
virtual AST * Optimize(Normalization normalization)=0
virtual void Assemble(Program &program, MonoAllocator &allocator, AString &normalized)=0
static ALIB_API Parser * Create(Compiler &compiler)
Definition parser.cpp:19
virtual detail::AST * Parse(const String &expressionString, NumberFormat *numberFormat)=0
static ALIB_API AST * Decompile(Program &program, MonoAllocator &allocator)