ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
compiler.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2025 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
7#include "alib_precompile.hpp"
8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Symbol ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
10#endif
11#if ALIB_C20_MODULES
12 module;
13#endif
14// ====================================== Global Fragment ======================================
18// =========================================== Module ==========================================
19#if ALIB_C20_MODULES
20 module ALib.Expressions;
22 import ALib.Lang;
23 import ALib.Strings;
24 import ALib.Boxing;
25 import ALib.EnumRecords;
27 import ALib.Variables;
28#else
30#endif
31// ====================================== Implementation =======================================
32namespace alib { namespace expressions {
33
34using namespace detail;
35
36// #################################################################################################
37// Scope constructor, Clear()
38// #################################################################################################
39Scope::Scope( SPFormatter& formatter) // evaluation scope constructor using an own allocator
40: EvalScopeAllocator(MonoAllocator::Create(ALIB_DBG("ExpressionScope",) 1, 200))
43, Formatter (formatter)
44, NamedResources (nullptr)
47, DCS ("ExpressionEvalScope")
48#endif
49{}
50
51Scope::Scope( MonoAllocator& allocator, SPFormatter& formatter )
52: EvalScopeAllocator(nullptr) // compile-time scope constructor using the allocator of the expression
53, Allocator (allocator)
55, Formatter (formatter)
57 NString,
59, EvalScopeVMMembers(nullptr)
61, DCS ("ExpressionCTScope")
62#endif
63{}
64
65Scope::~Scope()
66{
67 // Destruct members in vectors and tables.
71 {
74 }
75}
76
77
78void Scope::freeResources()
79{
80 Stack->clear();
81
82 if ( NamedResources )
83 for( auto& resource : *NamedResources )
84 lang::Destruct(*resource.second);
85}
86
87void Scope::Reset()
88{
89 ALIB_ASSERT( !IsCompileTime(), "EXPR" )
90
91 // save sizes
92 auto stackSize= Stack->size();
93 auto nestedExpressionsSize= EvalScopeVMMembers->NestedExpressions.size();
94
95 // free and destruct
99 Allocator.Reset(sizeof(MonoAllocator), alignof(MonoAllocator));
100
101 // create new
104
105 // reserve storage of the previous sizes for the next run.
106 Stack->reserve( stackSize );
107 EvalScopeVMMembers->NestedExpressions.reserve(nestedExpressionsSize );
108}
109
110
111// #################################################################################################
112// Constructor & Setup
113// #################################################################################################
115: allocator (ALIB_DBG("ExpressionCompiler",) 4)
116, typeMap (allocator, 2.0, 5.0) // we don't care about speed here, just for log output
123{
124 // create a clone of the default formatter.
126
127 // register compiler types
128 constexpr std::pair<Box&,NString> typeKeys[]=
129 {
130 { Types::Void , "T_VOID" },
131 { Types::Boolean , "T_BOOL" },
132 { Types::Integer , "T_INT" },
133 { Types::Float , "T_FLOAT" },
134 { Types::String , "T_STR" },
136 { Types::DateTime , "T_DATE" },
137 { Types::Duration , "T_DUR" }, )
138 };
139
140 size_t idx= sizeof( typeKeys ) / sizeof( std::pair<Box&, NString> );
141 do
142 {
143 --idx;
144 auto& name= EXPRESSIONS.GetResource( typeKeys[idx].second );
145 ALIB_STRINGS_TO_NARROW( name, nameNarrow, 128 )
146 AddType( typeKeys[idx].first, nameNarrow );
147 }
148 while( idx != 0 );
149
150 // load nested expression function descriptor
153}
154
156{
157 if( Repository != nullptr )
158 delete Repository;
159}
160
162{
163 auto* result= ctAllocator().New<Scope>( ctAllocator, CfgFormatter );
164 return result;
165}
166
168{
169 //------------- add default unary ops ----------
171 {
173 ALIB_ASSERT_ERROR( enumRecordIt.Enum() == DefaultUnaryOperators::NONE, "EXPR",
174 "Expected none-operator as first enum record" )
175 while( ++enumRecordIt != EnumRecords<DefaultUnaryOperators>::end() )
176 AddUnaryOperator( enumRecordIt->EnumElementName );
177
178 // default unary op aliases
180 {
181 // Not -> !
183 if( record.Symbol.IsNotEmpty() )
184 AlphabeticUnaryOperatorAliases.EmplaceOrAssign( record.Symbol,
185 record.Replacement );
186 }
187 }
188
189 //------------- add default binary ops ----------
191 {
193 ALIB_ASSERT_ERROR( enumRecordIt.Enum() == DefaultBinaryOperators::NONE, "EXPR",
194 "Expected none-operator as first enum record" )
195 while( ++enumRecordIt != EnumRecords<DefaultBinaryOperators>::end() ) {
196 // get symbol
197 if ( enumRecordIt->Symbol.Equals<NC>(A_CHAR("[]"))
199 continue;
200
201 // use equal operator's precedence for assign operator, if aliased.
202 auto precedence = ( enumRecordIt.Enum() == DefaultBinaryOperators::Assign
203 && HasBits(CfgCompilation,
206 : enumRecordIt->Precedence;
207
208 AddBinaryOperator(enumRecordIt->Symbol, precedence);
209 }
210
211 // default binary op aliases
214 AlphabeticBinaryOperatorAliases.EmplaceOrAssign( enumEntry.Symbol,
215 enumEntry.Replacement );
216 }
217
218
219 //------------- add default plug-ins ----------
220 CfgNormalizationDisallowed.emplace_back( A_CHAR("--") );
221 CfgNormalizationDisallowed.emplace_back( A_CHAR("++") );
222
225
228
231
234
237
239 if( HasBits( CfgBuiltInPlugins, BuiltInPlugins::DateAndTime ) )
241}
242
243// #############################################################################################
244// Parse and compile
245// #############################################################################################
246Expression Compiler::Compile( const String& expressionString )
247{
248 // checks
249 ALIB_ASSERT_ERROR( HasPlugins(), "EXPR",
250 "No plug-ins attached. Invoke SetupDefaults() on compiler instance." )
251 ALIB_ASSERT_ERROR( expressionString.IsNotNull(), "EXPR", "Nulled expression string." )
252 if( expressionString.IsEmpty() )
254
255
256 Expression expression( 1, 100 );
257 expression.ConstructT( expression.GetAllocator(),
258 expressionString,
259 createCompileTimeScope(expression.GetAllocator()) );
260
261 // parser
262 if (parser == nullptr)
263 parser= Parser::Create( *this );
264
265 AST* ast = nullptr;
266
267 // prevent cleaning memory with recursive compilation (may happen with nested expressions)
268 static integer recursionCounter= 0;
269 monomem::Snapshot startOfCompilation;
270 if( recursionCounter++ == 0 )
271 startOfCompilation= allocator.TakeSnapshot();
272
273 try
274 {
275 ALIB_DBG( Ticks startTime; )
276
277 // parse
278 ast= static_cast<AST*>(parser->Parse( expressionString, &CfgFormatter->DefaultNumberFormat ));
279
280 ALIB_DBG(
281 expression->DbgParseTime= startTime.Age();
282 startTime= Ticks::Now();
283 )
284
285 // optimize on AST level
286 ast= ast->Optimize( CfgNormalization );
287
288 // create program
289 expression->program= new detail::Program( *this, *expression, &allocator );
290
291 // assemble
292 ast->Assemble( *static_cast<detail::Program*>(expression->program), allocator, expression->normalizedString );
293 expression->normalizedString.TrimEnd();
294
295 static_cast<detail::Program*>(expression->program)->AssembleFinalize();
296 ALIB_DBG( expression->DbgAssemblyTime= startTime.Age(); )
297
298 if(--recursionCounter == 0)
299 allocator.Reset( startOfCompilation );
300
301 // checks
303 !static_cast<detail::Program*>(expression->program)->ResultType().IsType<void>(),
304 "EXPR", "No exception when parsing expression, but result type is void!" )
305
307 !static_cast<detail::Program*>(expression->program)->ResultType().IsType<void>(),
308 "EXPR", "No exception when parsing expression, but result type is void." )
309 }
310 catch( Exception& )
311 {
312 expression= nullptr;
313 if(--recursionCounter == 0)
314 allocator.Reset( startOfCompilation );
315 throw;
316 }
317 catch( std::exception& )
318 {
319 expression= nullptr;
320 if(--recursionCounter == 0)
321 allocator.Reset( startOfCompilation );
322 throw;
323 }
324
325 // Assert that nobody touches this allocator from now on. With evaluations,
326 // exclusively the evaluation scope is to be used.
327 expression->ctScope->Allocator.DbgLock(true);
328
329 return Expression(expression);
330}
331
333{
334 detail::AST* ast= nullptr;
335 auto startOfDecompilation= allocator.TakeSnapshot();
336 try
337 {
338 expression.allocator.DbgLock(false);
339 ast = detail::VirtualMachine::Decompile( *static_cast<detail::Program*>(expression.program),
340 allocator );
341 detail::Program* program= allocator().New<detail::Program>( *this, expression, nullptr );
342 ast->Assemble( *program, allocator, expression.optimizedString );
343 program->AssembleFinalize();
344 lang::Destruct(*program);
345 expression.allocator.DbgLock(true);
346 }
347 catch(Exception& )
348 {
349 allocator.Reset( startOfDecompilation );
350 throw;
351 }
352 allocator.Reset( startOfDecompilation );
353}
354
355
356// #############################################################################################
357// Manage named expressions
358// #############################################################################################
359
360bool Compiler::AddNamed( const String& name, const String& expressionString )
361{
362 String128 key;
364 key << name;
366 key.ToUpper();
367
368 auto it= namedExpressions.Find( key );
369 bool existed= it != namedExpressions.end();
370
371 // removal requested?
372 if( expressionString.IsNull() )
373 {
374 if ( existed )
375 {
376 namedExpressions.erase( it );
377 return true;
378 }
379 return false;
380 }
381
382 auto compiledExpression= Compile( expressionString );
383 compiledExpression->allocator.DbgLock(false);
384 compiledExpression->name.Allocate( compiledExpression->allocator, name);
385 compiledExpression->allocator.DbgLock(true);
386 ALIB_ASSERT( compiledExpression, "EXPR" )
387 if( existed )
388 it.Mapped()= compiledExpression;
389 else
390 namedExpressions.EmplaceUnique( key, compiledExpression );
391 return existed;
392}
393
395{
396 // search
397 String128 key;
399 key << name;
401 key.ToUpper();
402
403 auto it= namedExpressions.Find( key );
404 if( it != namedExpressions.end() )
405 return it.Mapped();
406
407 // not found! -> use protected, virtual method to get the string from somewhere
408 AString expressionString;
409 if (Repository == nullptr || !Repository->Get( name, expressionString ) )
411
412 // Got an expression string! -> Compile
413 Expression parsedExpression= Compile( expressionString );
414
415 parsedExpression->allocator.DbgLock(false);
416 parsedExpression->name.Allocate( parsedExpression->allocator, name );
417 parsedExpression->allocator.DbgLock(true);
418
419 Expression sharedExpression( parsedExpression );
420 namedExpressions.EmplaceUnique( key, sharedExpression );
421
422 return sharedExpression;
423}
424
425// #################################################################################################
426// Helpers
427// #################################################################################################
428void Compiler::AddType( Type sample, const NString& name )
429{
430 ALIB_DBG( auto it= )
431 typeMap.EmplaceIfNotExistent( &sample.TypeID(), name );
432 ALIB_ASSERT_ERROR( it.second == true, // is insert
433 "EXPR", "Type already registered with compiler." )
434}
435
437{
438 if( box.IsType<void>() )
439 return "NONE";
440
441 auto entry= typeMap.Find( &box.TypeID() );
442 ALIB_ASSERT_WARNING( entry != typeMap.end(), "EXPR",
443 "Custom type \"{}\" not registered. Please use Compiler::AddType to do so.", &box.TypeID() )
444 if( entry == typeMap.end() )
445 return "Unknown Type";
446
447 return entry.Mapped();
448}
449
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}
474
476 ArgIterator end,
477 AString& target )
478{
479 std::vector<Box*> buf;
480 buf.reserve( size_t(end - begin) );
481 while( begin != end )
482 buf.emplace_back( &*begin++ );
483 WriteFunctionSignature( buf.data(), buf.size(), target );
484}
485
486
487
488}} // namespace [alib::expressions]
bool IsType() const
const std::type_info & TypeID() const
Definition box.inl:827
Normalization CfgNormalization
Definition compiler.inl:265
Compilation CfgCompilation
Compilation flags.
Definition compiler.inl:261
List< MonoAllocator, String > UnaryOperators
Definition compiler.inl:108
virtual ALIB_DLL Expression Compile(const String &expressionString)
Definition compiler.cpp:246
ALIB_DLL NString TypeName(Type box)
Definition compiler.cpp:436
StringVectorMA CfgNormalizationDisallowed
Definition compiler.inl:286
ALIB_DLL void WriteFunctionSignature(Box **boxArray, size_t qty, AString &target)
Definition compiler.cpp:450
virtual ALIB_DLL Expression GetNamed(const String &name)
Definition compiler.cpp:394
BuiltInPlugins CfgBuiltInPlugins
Definition compiler.inl:227
void AddBinaryOperator(const String &symbol, int precedence)
Definition compiler.inl:166
strings::util::Token CfgNestedExpressionFunction
Definition compiler.inl:252
virtual ALIB_DLL bool AddNamed(const String &name, const String &expressionString)
Definition compiler.cpp:360
ExpressionRepository * Repository
Definition compiler.inl:310
ALIB_DLL void getOptimizedExpressionString(ExpressionVal &expression)
Definition compiler.cpp:332
HashMap< MonoAllocator, String, int > BinaryOperators
Definition compiler.inl:157
ALIB_DLL void SetupDefaults()
Definition compiler.cpp:167
void AddUnaryOperator(const String &symbol)
Definition compiler.inl:137
@ AutoCast
Installs plugins::AutoCast.
Definition compiler.inl:206
@ IF_ALIB_CAMP
Installs plugins::DateAndTime. )
Definition compiler.inl:210
@ Arithmetics
Installs plugins::Arithmetics.
Definition compiler.inl:207
@ Strings
Installs plugins::Strings.
Definition compiler.inl:209
@ ElvisOperator
Installs plugins::ElvisOperator.
Definition compiler.inl:205
detail::Parser * parser
The expression parser.
Definition compiler.inl:77
virtual ALIB_DLL Scope * createCompileTimeScope(MonoAllocator &expressionAllocator)
Definition compiler.cpp:161
ALIB_DLL void AddType(Type sample, const NString &name)
Definition compiler.cpp:428
HashMap< MonoAllocator, AString, Expression, std::hash< String >, std::equal_to< String > > namedExpressions
The map of 'named' expressions.
Definition compiler.inl:89
HashMap< MonoAllocator, String, String, alib::hash_string_ignore_case< character >, alib::equal_to_string_ignore_case< character > > AlphabeticUnaryOperatorAliases
Definition compiler.inl:119
HashMap< MonoAllocator, lang::TypeFunctors::Key, NAString, lang::TypeFunctors::Hash, lang::TypeFunctors::EqualTo > typeMap
The map of Type names and bit flag values.
Definition compiler.inl:83
virtual ALIB_DLL ~Compiler()
Destructor.
Definition compiler.cpp:155
HashMap< MonoAllocator, String, String, alib::hash_string_ignore_case< character >, alib::equal_to_string_ignore_case< character > > AlphabeticBinaryOperatorAliases
Definition compiler.inl:129
detail::ProgramBase * program
The compiled expression program.
ALIB_DLL const Box & ResultType() const
Definition program.inl:153
static ALIB_DLL SPFormatter Default
void InsertPlugin(CompilerPlugin *plugin, lang::Responsibility responsibility=lang::Responsibility::KeepWithSender)
Definition plugins.inl:129
void DbgLock(bool onOff) noexcept
void ConstructT(TArgs &&... args)
AllocatorType & GetAllocator() noexcept
TAString & ToUpper(integer regionStart=0, integer regionLength=MAX_LEN)
void DbgDisableBufferReplacementWarning()
Definition tastring.inl:245
constexpr bool IsEmpty() const
Definition string.inl:367
constexpr bool IsNotNull() const
Definition string.inl:357
constexpr bool IsNull() const
Definition string.inl:352
#define ALIB_CALLER_NULLED
Definition alib.inl:1010
#define ALIB_CALLER
Definition alib.inl:1001
#define A_CHAR(STR)
#define ALIB_ASSERT(cond, domain)
Definition alib.inl:1048
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
#define ALIB_ASSERT_WARNING(cond, domain,...)
Definition alib.inl:1050
#define ALIB_DBG(...)
Definition alib.inl:836
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1049
#define ALIB_DEBUG_CRITICAL_SECTIONS
Definition prepro.md:43
const RecordsTraits< TEnum >::Type & GetRecord(TEnum element)
Definition records.inl:188
StdVectorMono< Box >::iterator ArgIterator
@ Equal
Equal operator ('=='). Precedence 500.
const alib::boxing::Box & Type
@ 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.
void Destruct(T &object)
Definition tmp.inl:83
@ Transfer
Transfers responsibility to the receiving party.
void LoadResourcedTokens(camp::Camp &module, const NString &resourceName, strings::util::Token *target, int dbgSizeVerifier, character outerSeparator=',', character innerSeparator=' ')
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
std::vector< T, SCAMono< T > > StdVectorMono
Type alias in namespace alib.
LocalString< 128 > String128
Type alias name for TLocalString<character,128>.
expressions::Expression Expression
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
strings::TString< nchar > NString
Type alias in namespace alib.
Definition string.inl:2390
containers::HashMap< TAllocator, TKey, TMapped, THash, TEqual, THashCaching, TRecycling > HashMap
Type alias in namespace alib.
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
enumrecords::EnumRecords< TEnum > EnumRecords
Type alias in namespace alib.
Definition records.inl:519
boxing::Box Box
Type alias in namespace alib.
Definition box.inl:1216
exceptions::Exception Exception
Type alias in namespace alib.
containers::SharedPtr< format::Formatter > SPFormatter
Definition formatter.inl:42
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2381
expressions::ExpressionsCamp EXPRESSIONS
The singleton instance of ALib Camp class ExpressionsCamp.
time::Ticks Ticks
Type alias in namespace alib.
Definition ticks.inl:109
static ForwardIterator begin()
Definition records.inl:409
static constexpr ForwardIterator end()
Definition records.inl:419
Members used by the virtual machine. This is constructed only with evaluation-time scopes.
Definition scope.inl:69
VMMembers * EvalScopeVMMembers
The members used for the virtual machine. Available only with evaluation-time instances.
Definition scope.inl:129
StdVectorMono< Box > * Stack
Definition scope.inl:106
virtual ALIB_DLL void freeResources()
This method is called in the destructor, as well as in method Reset.
Definition compiler.cpp:78
MonoAllocator & Allocator
Definition scope.inl:101
HashMap< MonoAllocator, NString, ScopeResource * > * NamedResources
Definition scope.inl:126
SPFormatter Formatter
Definition scope.inl:120
lang::DbgCriticalSections DCS
Definition scope.inl:134
MonoAllocator * EvalScopeAllocator
Definition scope.inl:93
static ALIB_DLL Box Duration
Sample type-box for values of type DateTime::Duration).
static ALIB_DLL Box Integer
Sample type-box for integer types. (Precisely for type integer.)
static ALIB_DLL Box Boolean
Sample type-box for C++ type bool.
static ALIB_DLL Box Void
Sample type-box for C++ type void.
static ALIB_DLL Box Float
Sample type-box for C++ type double.
static ALIB_DLL Box DateTime
Sample type-box for date and time values of type DateTime).
static ALIB_DLL Box String
virtual AST * Optimize(Normalization normalization)=0
virtual void Assemble(Program &program, MonoAllocator &allocator, AString &normalized)=0
static ALIB_DLL Parser * Create(Compiler &compiler)
Definition parser.cpp:29
static ALIB_DLL AST * Decompile(Program &program, MonoAllocator &allocator)