ALib C++ Library
Library Version: 2511 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;
21 import ALib.Expressions.Impl;
22 import ALib.Lang;
23 import ALib.Strings;
24 import ALib.Boxing;
25 import ALib.EnumRecords;
26 import ALib.EnumRecords.Bootstrap;
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 // Destruct members in vectors and tables.
69 if ( EvalScopeAllocator ) {
72} }
73
74
75void Scope::freeResources() {
76 Stack->clear();
77
78 if ( NamedResources )
79 for( auto& resource : *NamedResources )
80 lang::Destruct(*resource.second);
81}
82
83void Scope::Reset() {
84 ALIB_ASSERT( !IsCompileTime(), "EXPR" )
85
86 // save sizes
87 auto stackSize= Stack->size();
88 auto nestedExpressionsSize= EvalScopeVMMembers->NestedExpressions.size();
89
90 // free and destruct
94 Allocator.Reset(sizeof(MonoAllocator), alignof(MonoAllocator));
95
96 // create new
99
100 // reserve storage of the previous sizes for the next run.
101 Stack->reserve( stackSize );
102 EvalScopeVMMembers->NestedExpressions.reserve(nestedExpressionsSize );
103}
104
105
106//##################################################################################################
107// Constructor & Setup
108//##################################################################################################
110: allocator (ALIB_DBG("ExpressionCompiler",) 4)
111, typeMap (allocator, 2.0, 5.0) // we don't care about speed here, just for log output
118 // create a clone of the default formatter.
120
121 // register compiler types
122 constexpr std::pair<Box&,NString> typeKeys[]=
123 {
124 { Types::Void , "T_VOID" },
125 { Types::Boolean , "T_BOOL" },
126 { Types::Integer , "T_INT" },
127 { Types::Float , "T_FLOAT" },
128 { Types::String , "T_STR" },
130 { Types::DateTime , "T_DATE" },
131 { Types::Duration , "T_DUR" }, )
132 };
133
134 size_t idx= sizeof( typeKeys ) / sizeof( std::pair<Box&, NString> );
135 do
136 {
137 --idx;
138 auto& name= EXPRESSIONS.GetResource( typeKeys[idx].second );
139 ALIB_STRINGS_TO_NARROW( name, nameNarrow, 128 )
140 AddType( typeKeys[idx].first, nameNarrow );
141 }
142 while( idx != 0 );
143
144 // load nested expression function descriptor
147}
148
149Compiler::~Compiler() { if( Repository != nullptr ) delete Repository; }
150
152{
153 auto* result= ctAllocator().New<Scope>( ctAllocator, CfgFormatter );
154 return result;
155}
156
158 //------------------------------------- add default unary ops ------------------------------------
161 ALIB_ASSERT_ERROR( enumRecordIt.Enum() == DefaultUnaryOperators::NONE, "EXPR",
162 "Expected none-operator as first enum record" )
163 while( ++enumRecordIt != EnumRecords<DefaultUnaryOperators>::end() )
164 AddUnaryOperator( enumRecordIt->EnumElementName );
165
166 // default unary op aliases
168 // Not -> !
170 if( record.Symbol.IsNotEmpty() )
171 AlphabeticUnaryOperatorAliases.EmplaceOrAssign( record.Symbol,
172 record.Replacement );
173 } }
174
175 //------------------------------------- add default binary ops -----------------------------------
178 ALIB_ASSERT_ERROR( enumRecordIt.Enum() == DefaultBinaryOperators::NONE, "EXPR",
179 "Expected none-operator as first enum record" )
180 while( ++enumRecordIt != EnumRecords<DefaultBinaryOperators>::end() ) {
181 // get symbol
182 if ( enumRecordIt->Symbol.Equals<NC>(A_CHAR("[]"))
184 continue;
185
186 // use equal operator's precedence for assign operator, if aliased.
187 auto precedence = ( enumRecordIt.Enum() == DefaultBinaryOperators::Assign
188 && HasBits(CfgCompilation,
191 : enumRecordIt->Precedence;
192
193 AddBinaryOperator(enumRecordIt->Symbol, precedence);
194 }
195
196 // default binary op aliases
199 AlphabeticBinaryOperatorAliases.EmplaceOrAssign( enumEntry.Symbol,
200 enumEntry.Replacement );
201 }
202
203
204 //---------------------------------------- add default plug --------------------------------------
205 CfgNormalizationDisallowed.emplace_back( A_CHAR("--") );
206 CfgNormalizationDisallowed.emplace_back( A_CHAR("++") );
207
210
213
216
219
222
224 if( HasBits( CfgBuiltInPlugins, BuiltInPlugins::DateAndTime ) )
226}
227
228//##################################################################################################
229// Parse and compile
230//##################################################################################################
231Expression Compiler::Compile( const String& expressionString ) {
232 // checks
233 ALIB_ASSERT_ERROR( HasPlugins(), "EXPR",
234 "No plug-ins attached. Invoke SetupDefaults() on compiler instance." )
235 ALIB_ASSERT_ERROR( expressionString.IsNotNull(), "EXPR", "Nulled expression string." )
236 if( expressionString.IsEmpty() )
238
239
240 Expression expression( 1, 100 );
241 expression.ConstructT( expression.GetAllocator(),
242 expressionString,
243 createCompileTimeScope(expression.GetAllocator()) );
244
245 // parser
246 if (parser == nullptr)
247 parser= Parser::Create( *this );
248
249 AST* ast = nullptr;
250
251 // prevent cleaning memory with recursive compilation (may happen with nested expressions)
252 static integer recursionCounter= 0;
253 monomem::Snapshot startOfCompilation;
254 if( recursionCounter++ == 0 )
255 startOfCompilation= allocator.TakeSnapshot();
256
257 try
258 {
259 ALIB_DBG( Ticks startTime; )
260
261 // parse
262 ast= static_cast<AST*>(parser->Parse( expressionString, &CfgFormatter->DefaultNumberFormat ));
263
264 ALIB_DBG(
265 expression->DbgParseTime= startTime.Age();
266 startTime= Ticks::Now();
267 )
268
269 // optimize on AST level
270 ast= ast->Optimize( CfgNormalization );
271
272 // create program
273 expression->program= new detail::Program( *this, *expression, &allocator );
274
275 // assemble
276 ast->Assemble( *static_cast<detail::Program*>(expression->program), allocator,
277 expression->normalizedString );
278 expression->normalizedString.TrimEnd();
279
280 static_cast<detail::Program*>(expression->program)->AssembleFinalize();
281 ALIB_DBG( expression->DbgAssemblyTime= startTime.Age(); )
282
283 if(--recursionCounter == 0)
284 allocator.Reset( startOfCompilation );
285
286 // checks
288 !static_cast<detail::Program*>(expression->program)->ResultType().IsType<void>(),
289 "EXPR", "No exception when parsing expression, but result type is void!" )
290
292 !static_cast<detail::Program*>(expression->program)->ResultType().IsType<void>(),
293 "EXPR", "No exception when parsing expression, but result type is void." )
294 }
295 catch( Exception& )
296 {
297 expression= nullptr;
298 if(--recursionCounter == 0)
299 allocator.Reset( startOfCompilation );
300 throw;
301 }
302 catch( std::exception& )
303 {
304 expression= nullptr;
305 if(--recursionCounter == 0)
306 allocator.Reset( startOfCompilation );
307 throw;
308 }
309
310 // Assert that nobody touches this allocator from now on. With evaluations,
311 // exclusively the evaluation scope is to be used.
312 expression->ctScope->Allocator.DbgLock(true);
313
314 return Expression(expression);
315}
316
318 detail::AST* ast= nullptr;
319 auto startOfDecompilation= allocator.TakeSnapshot();
320 try
321 {
322 expression.allocator.DbgLock(false);
323 ast = detail::VirtualMachine::Decompile( *static_cast<detail::Program*>(expression.program),
324 allocator );
325 detail::Program* program= allocator().New<detail::Program>( *this, expression, nullptr );
326 ast->Assemble( *program, allocator, expression.optimizedString );
327 program->AssembleFinalize();
328 lang::Destruct(*program);
329 expression.allocator.DbgLock(true);
330 }
331 catch(Exception& )
332 {
333 allocator.Reset( startOfDecompilation );
334 throw;
335 }
336 allocator.Reset( startOfDecompilation );
337}
338
339
340//##################################################################################################
341// Manage named expressions
342//##################################################################################################
343
344bool Compiler::AddNamed( const String& name, const String& expressionString ) {
345 String128 key;
347 key << name;
349 key.ToUpper();
350
351 auto it= namedExpressions.Find( key );
352 bool existed= it != namedExpressions.end();
353
354 // removal requested?
355 if( expressionString.IsNull() ) {
356 if ( existed ) {
357 namedExpressions.erase( it );
358 return true;
359 }
360 return false;
361 }
362
363 auto compiledExpression= Compile( expressionString );
364 compiledExpression->allocator.DbgLock(false);
365 compiledExpression->name.Allocate( compiledExpression->allocator, name);
366 compiledExpression->allocator.DbgLock(true);
367 ALIB_ASSERT( compiledExpression, "EXPR" )
368 if( existed )
369 it.Mapped()= compiledExpression;
370 else
371 namedExpressions.EmplaceUnique( key, compiledExpression );
372 return existed;
373}
374
376 // search
377 String128 key;
379 key << name;
381 key.ToUpper();
382
383 auto it= namedExpressions.Find( key );
384 if( it != namedExpressions.end() )
385 return it.Mapped();
386
387 // not found! -> use protected, virtual method to get the string from somewhere
388 AString expressionString;
389 if (Repository == nullptr || !Repository->Get( name, expressionString ) )
391
392 // Got an expression string! -> Compile
393 Expression parsedExpression= Compile( expressionString );
394
395 parsedExpression->allocator.DbgLock(false);
396 parsedExpression->name.Allocate( parsedExpression->allocator, name );
397 parsedExpression->allocator.DbgLock(true);
398
399 Expression sharedExpression( parsedExpression );
400 namedExpressions.EmplaceUnique( key, sharedExpression );
401
402 return sharedExpression;
403}
404
405//##################################################################################################
406// Helpers
407//##################################################################################################
408void Compiler::AddType( Type sample, const NString& name ) {
409 ALIB_DBG( auto it= )
410 typeMap.EmplaceIfNotExistent( &sample.TypeID(), name );
411 ALIB_ASSERT_ERROR( it.second == true, // is insert
412 "EXPR", "Type already registered with compiler." )
413}
414
416 if( box.IsType<void>() )
417 return "NONE";
418
419 auto entry= typeMap.Find( &box.TypeID() );
420 ALIB_ASSERT_WARNING( entry != typeMap.end(), "EXPR",
421 "Custom type \"{}\" not registered. Please use Compiler::AddType to do so.", &box.TypeID() )
422 if( entry == typeMap.end() )
423 return "Unknown Type";
424
425 return entry.Mapped();
426}
427
428void Compiler::WriteFunctionSignature( Box** boxArray, size_t qty, AString& target ) {
429 bool variadic= qty && (*(boxArray + qty -1)) == nullptr;
430 if( variadic )
431 --qty;
432
433 target<< '(';
434 bool isFirst= true;
435 for( size_t i= 0 ; i < qty ; ++i ) {
436 if(!isFirst)
437 target<< ", ";
438 isFirst= false;
439 target << '<' << TypeName( **boxArray++ ) << '>';
440 }
441 if(variadic) {
442 if(!isFirst)
443 target<< ", ";
444 target<< "...";
445 }
446
447 target<< ')';
448}
449
451 ArgIterator end,
452 AString& target ) {
453 std::vector<Box*> buf;
454 buf.reserve( size_t(end - begin) );
455 while( begin != end )
456 buf.emplace_back( &*begin++ );
457 WriteFunctionSignature( buf.data(), buf.size(), target );
458}
459
460
461
462}} // namespace [alib::expressions]
bool IsType() const
const std::type_info & TypeID() const
Definition box.inl:780
Normalization CfgNormalization
Definition compiler.inl:260
ListMA< String > UnaryOperators
Definition compiler.inl:106
Compilation CfgCompilation
Compilation flags.
Definition compiler.inl:256
virtual ALIB_DLL Expression Compile(const String &expressionString)
Definition compiler.cpp:231
ALIB_DLL NString TypeName(Type box)
Definition compiler.cpp:415
StringVectorMA CfgNormalizationDisallowed
Definition compiler.inl:281
ALIB_DLL void WriteFunctionSignature(Box **boxArray, size_t qty, AString &target)
Definition compiler.cpp:428
virtual ALIB_DLL Expression GetNamed(const String &name)
Definition compiler.cpp:375
BuiltInPlugins CfgBuiltInPlugins
Definition compiler.inl:222
void AddBinaryOperator(const String &symbol, int precedence)
Definition compiler.inl:163
strings::util::Token CfgNestedExpressionFunction
Definition compiler.inl:247
virtual ALIB_DLL bool AddNamed(const String &name, const String &expressionString)
Definition compiler.cpp:344
ExpressionRepository * Repository
Definition compiler.inl:305
ALIB_DLL void getOptimizedExpressionString(ExpressionVal &expression)
Definition compiler.cpp:317
HashMap< MonoAllocator, String, int > BinaryOperators
Definition compiler.inl:154
ALIB_DLL void SetupDefaults()
Definition compiler.cpp:157
void AddUnaryOperator(const String &symbol)
Definition compiler.inl:135
@ AutoCast
Installs plugins::AutoCast.
Definition compiler.inl:201
@ IF_ALIB_CAMP
Installs plugins::DateAndTime. )
Definition compiler.inl:205
@ Arithmetics
Installs plugins::Arithmetics.
Definition compiler.inl:202
@ Strings
Installs plugins::Strings.
Definition compiler.inl:204
@ ElvisOperator
Installs plugins::ElvisOperator.
Definition compiler.inl:200
detail::Parser * parser
The expression parser.
Definition compiler.inl:75
virtual ALIB_DLL Scope * createCompileTimeScope(MonoAllocator &expressionAllocator)
Definition compiler.cpp:151
ALIB_DLL void AddType(Type sample, const NString &name)
Definition compiler.cpp:408
HashMap< MonoAllocator, AString, Expression, std::hash< String >, std::equal_to< String > > namedExpressions
The map of 'named' expressions.
Definition compiler.inl:87
HashMap< MonoAllocator, String, String, alib::hash_string_ignore_case< character >, alib::equal_to_string_ignore_case< character > > AlphabeticUnaryOperatorAliases
Definition compiler.inl:117
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:81
virtual ALIB_DLL ~Compiler()
Destructor.
Definition compiler.cpp:149
HashMap< MonoAllocator, String, String, alib::hash_string_ignore_case< character >, alib::equal_to_string_ignore_case< character > > AlphabeticBinaryOperatorAliases
Definition compiler.inl:127
detail::ProgramBase * program
The compiled expression program.
ALIB_DLL const Box & ResultType() const
Definition program.inl:151
static ALIB_DLL SPFormatter Default
void InsertPlugin(CompilerPlugin *plugin, lang::Responsibility responsibility=lang::Responsibility::KeepWithSender)
Definition plugins.inl:124
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:244
constexpr bool IsEmpty() const
Definition string.inl:365
constexpr bool IsNotNull() const
Definition string.inl:355
constexpr bool IsNull() const
Definition string.inl:350
#define ALIB_CALLER_NULLED
Definition alib.inl:1027
#define ALIB_CALLER
Definition alib.inl:1018
#define A_CHAR(STR)
#define ALIB_ASSERT(cond, domain)
Definition alib.inl:1065
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
#define ALIB_ASSERT_WARNING(cond, domain,...)
Definition alib.inl:1067
#define ALIB_DBG(...)
Definition alib.inl:853
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
#define ALIB_DEBUG_CRITICAL_SECTIONS
Definition prepro.dox.md:43
const RecordsTraits< TEnum >::Type & GetRecord(TEnum element)
Definition records.inl:185
@ 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.
StdVectorMA< Box >::iterator ArgIterator
void Destruct(T &object)
Definition tmp.inl:82
@ 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.
LocalString< 128 > String128
Type alias name for TLocalString<character,128>.
std::vector< T, StdMA< T > > StdVectorMA
Type alias in namespace alib.
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:2198
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:482
boxing::Box Box
Type alias in namespace alib.
Definition box.inl:1149
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:2189
expressions::ExpressionsCamp EXPRESSIONS
The singleton instance of ALib Camp class ExpressionsCamp.
time::Ticks Ticks
Type alias in namespace alib.
Definition ticks.inl:79
static ForwardIterator begin()
Definition records.inl:378
static constexpr ForwardIterator end()
Definition records.inl:386
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
StdVectorMA< 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:75
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)