ALib C++ Library
Library Version: 2402 R1
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// #################################################################################################
8
9#if !defined(ALIB_DOX)
10#if !defined (HPP_ALIB_EXPRESSIONS_COMPILER)
12#endif
13#if !defined (HPP_ALIB_EXPRESSIONS_DETAIL_PARSER)
15#endif
16#if !defined (HPP_ALIB_EXPRESSIONS_DETAIL_AST)
18#endif
19#if !defined (HPP_ALIB_EXPRESSIONS_DETAIL_PROGRAM)
21#endif
22#if !defined (HPP_ALIB_EXPRESSIONS_PLUGINS_ELVIS)
24#endif
25#if !defined (HPP_ALIB_EXPRESSIONS_PLUGINS_AUTOCAST)
27#endif
28#if !defined (HPP_ALIB_EXPRESSIONS_PLUGINS_ARITHMETICS)
30#endif
31#if !defined (HPP_ALIB_EXPRESSIONS_PLUGINS_MATH)
33#endif
34#if !defined (HPP_ALIB_EXPRESSIONS_PLUGINS_STRINGS)
36#endif
37#if ALIB_CAMP && !defined (HPP_ALIB_EXPRESSIONS_PLUGINS_DATEANDTIME)
39#endif
40
41# if !defined (HPP_ALIB_LANG_CAMP_INLINES)
43# endif
44
45#endif // !defined(ALIB_DOX)
46
47namespace alib { namespace expressions {
48
49using namespace detail;
50
51// #################################################################################################
52// Scope constructor, Clear() (avoid an own compilation unit for now)
53// #################################################################################################
54Scope::Scope( SPFormatter& formatter )
55: Allocator ( 4 * 1024 )
56, CTScope ( nullptr )
57, NestedExpressions( Allocator )
58, Resources ( Allocator )
59, NamedResources ( &Allocator )
60, Formatter ( formatter )
61{
62 #if ALIB_DEBUG_MONOMEM
63 Allocator.LogDomain= "MA/EXPR/SCP";
64 #endif
65}
66
67void Scope::Reset()
68{
69 Stack.clear();
70 auto nestedExpressionsSize= NestedExpressions.size();
71 auto ResourcesSize= Resources.size();
72 auto NamedResourcesSize= NamedResources.Size();
73
74
75 for( auto* resource : Resources )
76 delete resource;
77
78 for( auto resource : NamedResources )
79 delete resource.second;
80
81 NamedResources.Reset();
82
86
87 // reserve storage of previous size for the next run.
88 NestedExpressions.reserve(nestedExpressionsSize );
89 Resources.reserve( ResourcesSize );
90 NamedResources.Reserve( NamedResourcesSize, lang::ValueReference::Absolute);
91}
92
93
94// #################################################################################################
95// Constructor & Setup
96// #################################################################################################
98: allocator ( 4 * 1024 )
99, typeMap ( &allocator, 2.0, 5.0) // we don't care about speed here, just for log output
100, namedExpressions ( &allocator )
101, UnaryOperators ( &allocator )
102, AlphabeticUnaryOperatorAliases ( &allocator )
103, AlphabeticBinaryOperatorAliases( &allocator )
104, BinaryOperators ( &allocator )
105{
106 #if ALIB_DEBUG_MONOMEM
107 allocator.LogDomain= "MA/EXPR/CMPLR";
108 #endif
109
110 // create a clone of the default formatter.
111 CfgFormatter.reset( Formatter::GetDefault()->Clone() );
112
113 // register compiler types
115 constexpr std::pair<Box&,NString> typeKeys[]=
116 {
117 { Types::Void , "T_VOID" },
118 { Types::Boolean , "T_BOOL" },
119 { Types::Integer , "T_INT" },
120 { Types::Float , "T_FLOAT" },
121 { Types::String , "T_STR" },
123 { Types::DateTime , "T_DATE" },
124 { Types::Duration , "T_DUR" }, )
125 };
127
128 size_t idx= sizeof( typeKeys ) / sizeof( std::pair<Box&, NString> );
129 do
130 {
131 --idx;
132 auto& name= EXPRESSIONS.GetResource( typeKeys[idx].second );
133 ALIB_STRINGS_TO_NARROW( name, nameNarrow, 128 )
134 AddType( typeKeys[idx].first, nameNarrow );
135 }
136 while( idx != 0 );
137
138 // load nested expression function descriptor
141}
142
144{
145 ALIB_ASSERT_ERROR( CfgFormatter.get()->CountAcquirements() == 0, "EXPR",
146 "The formatter of this compiler was not released properly" )
147 if( Repository != nullptr )
148 delete Repository;
149}
150
152{
153 auto* result= new Scope( CfgFormatter );
154 #if ALIB_DEBUG_MONOMEM
155 result->Allocator.LogDomain= "MA/EXPR/CTSCP";
156 #endif
157 return result;
158}
159
161{
162 //------------- add default unary ops ----------
164 {
166 ALIB_ASSERT_ERROR( enumRecordIt.Enum() == DefaultUnaryOperators::NONE, "EXPR",
167 "Expected none-operator as first enum record" )
168 while( ++enumRecordIt != EnumRecords<DefaultUnaryOperators>::end() )
169 AddUnaryOperator( enumRecordIt->EnumElementName );
170
171 // default unary op aliases
173 {
174 // Not -> !
176 if( record.Symbol.IsNotEmpty() )
177 AlphabeticUnaryOperatorAliases.EmplaceOrAssign( record.Symbol,
178 record.Replacement );
179 }
180 }
181
182 //------------- add default binary ops ----------
184 {
186 ALIB_ASSERT_ERROR( enumRecordIt.Enum() == DefaultBinaryOperators::NONE, "EXPR",
187 "Expected none-operator as first enum record" )
188 while( ++enumRecordIt != EnumRecords<DefaultBinaryOperators>::end() )
189 {
190 // get symbol
191 if( enumRecordIt->Symbol.Equals<false>( A_CHAR( "[]") )
193 continue;
194
195 // use equal operator's precedence for assign operator, if aliased.
196 auto precedence = ( enumRecordIt.Enum() == DefaultBinaryOperators::Assign
199 : enumRecordIt->Precedence;
200
201 AddBinaryOperator( enumRecordIt->Symbol, precedence );
202 }
203
204 // default binary op aliases
207 AlphabeticBinaryOperatorAliases.EmplaceOrAssign( enumEntry.Symbol,
208 enumEntry.Replacement );
209 }
210
211
212 //------------- add default plug-ins ----------
213 CfgNormalizationDisallowed.emplace_back( "--" );
214 CfgNormalizationDisallowed.emplace_back( "++" );
215
220
225
230
232 InsertPlugin( new plugins::Math(*this),
235
237 InsertPlugin( new plugins::Strings(*this),
240
242 if( HasBits( CfgBuiltInPlugins, BuiltInPlugins::DateAndTime ) )
246}
247
248// #############################################################################################
249// Parse and compile
250// #############################################################################################
251SPExpression Compiler::Compile( const String& expressionString )
252{
253 // checks
254 ALIB_ASSERT_ERROR( HasPlugins(), "EXPR",
255 "No plug-ins attached. Invoke SetupDefaults() on compiler instance." )
256 ALIB_ASSERT_ERROR( expressionString.IsNotNull(), "EXPR", "Nulled expression string." )
257 if( expressionString.IsEmpty() )
259
260
261 Expression* expression= new Expression( expressionString, getCompileTimeScope() );
262
263 // parser
264 if (parser == nullptr)
265 parser= Parser::Create( *this );
266
267 AST* ast = nullptr;
268
269 // prevent cleaning memory with recursive compilation (may happen with nested expressions)
270 static integer recursionCounter= 0;
271 MonoAllocator::Snapshot startOfCompilation;
272 if( recursionCounter++ == 0 )
273 startOfCompilation= allocator.TakeSnapshot();
274
275 try
276 {
277 #if ALIB_TIME && ALIB_DEBUG
278 Ticks startTime;
279 #endif
280
281
282 // parse
283 ast= parser->Parse( expressionString, &CfgFormatter->DefaultNumberFormat, &allocator );
284
285 #if ALIB_TIME && ALIB_DEBUG
286 expression->DbgParseTime= startTime.Age();
287 startTime= Ticks::Now();
288 #endif
289
290 // optimize on AST level
291 ast= ast->Optimize( CfgNormalization );
292
293 // create program
294 expression->program= new detail::Program( *this, *expression, &allocator );
295
296 // assemble
297 ast->Assemble( *expression->program, allocator, expression->normalizedString );
298 expression->normalizedString.TrimEnd();
299
300 expression->program->AssembleFinalize();
301 #if ALIB_TIME && ALIB_DEBUG
302 expression->DbgAssemblyTime= startTime.Age();
303 #endif
304
305 if(--recursionCounter == 0)
306 allocator.Reset( startOfCompilation );
307
308 // checks
309 ALIB_ASSERT_ERROR( !expression->program->ResultType().IsType<void>(), "EXPR",
310 "No exception when parsing expression, but result type is void!" )
311
312 ALIB_ASSERT_ERROR( !expression->program->ResultType().IsType<void>(), "EXPR",
313 "No exception when parsing expression, but result type is void." )
314 }
315 catch( Exception& )
316 {
317 delete expression;
318 if(--recursionCounter == 0)
319 allocator.Reset( startOfCompilation );
320 throw;
321 }
322 catch( std::exception& )
323 {
324 delete expression;
325 if(--recursionCounter == 0)
326 allocator.Reset( startOfCompilation );
327 throw;
328 }
329 return SPExpression(expression);
330}
331
333{
334 detail::AST* ast= nullptr;
335 auto startOfDecompilation= allocator.TakeSnapshot();
336 try
337 {
338 ast = detail::VirtualMachine::Decompile( *dynamic_cast<Program*>(expression->program), allocator );
339 detail::Program* program= allocator.Emplace<detail::Program>( *this, *expression, nullptr );
340 ast->Assemble( *program, allocator, expression->optimizedString );
341 program->AssembleFinalize();
342 monomem::Destruct(program);
343 }
344 catch(Exception& )
345 {
346 allocator.Reset( startOfDecompilation );
347 throw;
348 }
349 allocator.Reset( startOfDecompilation );
350}
351
352
353// #############################################################################################
354// Manage named expressions
355// #############################################################################################
356
357bool Compiler::AddNamed( const String& name, const String& expressionString )
358{
359 String128 key;
361 key << name;
363 key.ToUpper();
364
365 auto it= namedExpressions.Find( key );
366 bool existed= it != namedExpressions.end();
367
368 // removal requested?
369 if( expressionString.IsNull() )
370 {
371 if ( existed )
372 {
373 namedExpressions.Erase( it );
374 return true;
375 }
376 return false;
377 }
378
379 auto compiledExpression= Compile( expressionString );
380 compiledExpression->name= compiledExpression->ctScope->Allocator.EmplaceString( name );
381 ALIB_ASSERT( compiledExpression )
382 if( existed )
383 it.Mapped()= compiledExpression;
384 else
385 namedExpressions.EmplaceUnique( key, compiledExpression );
386 return existed;
387}
388
390{
391 // search
392 String128 key;
394 key << name;
396 key.ToUpper();
397
398 auto it= namedExpressions.Find( key );
399 if( it != namedExpressions.end() )
400 return it.Mapped();
401
402 // not found! -> use protected, virtual method to get the string from somewhere
403 AString expressionString;
404 if (Repository == nullptr || !Repository->Get( name, expressionString ) )
406
407 // Got an expression string! -> Compile
408 SPExpression parsedExpression= Compile( expressionString );
409
410 parsedExpression->name= parsedExpression->ctScope->Allocator.EmplaceString( name );
411
412 SPExpression sharedExpression( parsedExpression );
413 namedExpressions.EmplaceUnique( key, sharedExpression );
414
415 return sharedExpression;
416}
417
418
419
420// #################################################################################################
421// Helpers
422// #################################################################################################
423
424void Compiler::AddType( Type sample, const NString& name )
425{
426 ALIB_DBG( auto it= )
427 typeMap.EmplaceIfNotExistent( &sample.TypeID(), name );
428 ALIB_ASSERT_ERROR( it.second == true, "EXPR", // is insert
429 "Type already registered with compiler." )
430}
431
433{
434 if( box.IsType<void>() )
435 return "NONE";
436
437 auto entry= typeMap.Find( &box.TypeID() );
438 ALIB_ASSERT_WARNING( entry != typeMap.end(), "EXPR",
439 "Custom type {!Q} not registered. Please use Compiler::AddType to do so.",
440 box.TypeID() )
441 if( entry == typeMap.end() )
442 return "Unknown Type";
443
444 return entry.Mapped();
445}
446
448void Compiler::WriteFunctionSignature( Box** boxArray, size_t qty, AString& target )
449{
450 bool variadic= qty && (*(boxArray + qty -1)) == nullptr;
451 if( variadic )
452 --qty;
453
454 target<< '(';
455 bool isFirst= true;
456 for( size_t i= 0 ; i < qty ; ++i )
457 {
458 if(!isFirst)
459 target<< ", ";
460 isFirst= false;
461 target << '<' << TypeName( **boxArray++ ) << '>';
462 }
463 if(variadic)
464 {
465 if(!isFirst)
466 target<< ", ";
467 target<< "...";
468 }
469
470 target<< ')';
471}
473
475 ArgIterator end,
476 AString& target )
477{
478 std::vector<Box*> buf;
479 buf.reserve( static_cast<size_t>(end - begin) );
480 while( begin != end )
481 buf.emplace_back( &*begin++ );
482 WriteFunctionSignature( buf.data(), buf.size(), target );
483}
484
485
486
487}} // namespace [alib::expressions]
bool IsType() const
const std::type_info & TypeID() const
Definition box.inl:902
void AddBinaryOperator(const String &symbol, int precedence)
Definition compiler.hpp:208
HashMap< String, String, alib::hash_string_ignore_case< character >, alib::equal_to_string_ignore_case< character > > AlphabeticUnaryOperatorAliases
Definition compiler.hpp:154
HashMap< TypeFunctors::Key, NAString, TypeFunctors::Hash, TypeFunctors::EqualTo > typeMap
Definition compiler.hpp:116
virtual ALIB_API SPExpression Compile(const String &expressionString)
Definition compiler.cpp:251
virtual ALIB_API SPExpression GetNamed(const String &name)
Definition compiler.cpp:389
ALIB_API NString TypeName(Type box)
Definition compiler.cpp:432
ExpressionRepository * Repository
Definition compiler.hpp:374
ALIB_API void getOptimizedExpressionString(Expression *expression)
Definition compiler.cpp:332
ALIB_API void AddType(Type sample, const NString &name)
Definition compiler.cpp:424
virtual ALIB_API Scope * getCompileTimeScope()
Definition compiler.cpp:151
strings::util::Token CfgNestedExpressionFunction
Definition compiler.hpp:304
detail::Parser * parser
Definition compiler.hpp:111
virtual ALIB_API bool AddNamed(const String &name, const String &expressionString)
Definition compiler.cpp:357
Normalization CfgNormalization
Definition compiler.hpp:323
ALIB_API void WriteFunctionSignature(Box **boxArray, size_t qty, AString &target)
Definition compiler.cpp:448
ALIB_API void SetupDefaults()
Definition compiler.cpp:160
virtual ALIB_API ~Compiler()
Definition compiler.cpp:143
HashMap< String, String, alib::hash_string_ignore_case< character >, alib::equal_to_string_ignore_case< character > > AlphabeticBinaryOperatorAliases
Definition compiler.hpp:166
@ AutoCast
Installs plugins::AutoCast .
@ Arithmetics
Installs plugins::Arithmetics .
@ Strings
Installs plugins::Strings .
@ ALIB_IF_CAMP
Installs plugins::DateAndTime . )
@ ElvisOperator
Installs plugins::ElvisOperator .
HashMap< AString, SPExpression, std::hash< String >, std::equal_to< String > > namedExpressions
Definition compiler.hpp:121
std::vector< AString > CfgNormalizationDisallowed
Definition compiler.hpp:346
BuiltInPlugins CfgBuiltInPlugins
Definition compiler.hpp:275
void AddUnaryOperator(const String &symbol)
Definition compiler.hpp:176
virtual bool Get(const String &identifier, AString &target)=0
Ticks::Duration DbgAssemblyTime
ALIB_API const Box & ResultType() const
Definition program.cpp:55
static ALIB_API AST * Decompile(Program &program, MonoAllocator &allocator)
const String & GetResource(const NString &name)
void InsertPlugin(TPlugin *plugin, TPriorities priority, lang::Responsibility responsibility=lang::Responsibility::KeepWithSender)
static SPFormatter GetDefault()
ALIB_FORCE_INLINE T * Emplace(TArgs &&... args)
ALIB_API void Reset(const Snapshot &snapshot=Snapshot())
TAString & ToUpper(integer regionStart=0, integer regionLength=MAX_LEN)
Definition astring.hpp:1832
TAString & TrimEnd(const TCString< TChar > &trimChars=TT_StringConstants< TChar >::DefaultWhitespaces())
Definition astring.hpp:1679
void DbgDisableBufferReplacementWarning()
Definition astring.hpp:353
constexpr bool IsNull() const
Definition string.hpp:395
constexpr bool IsEmpty() const
Definition string.hpp:414
constexpr bool IsNotNull() const
Definition string.hpp:402
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:846
#define ALIB_CALLER
Definition alib.hpp:835
#define A_CHAR(STR)
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:715
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:644
#define ALIB_ASSERT_WARNING(cond,...)
Definition alib.hpp:985
#define ALIB_DBG(...)
Definition alib.hpp:457
#define ALIB_ASSERT(cond)
Definition alib.hpp:983
const T_EnumRecords< TEnum >::Type & GetRecord(TEnum element)
std::vector< Box >::iterator ArgIterator
@ Equal
Equal operator ('=='). Precedence 500.
std::shared_ptr< Expression > SPExpression
@ NamedExpressionNotFound
Compile-time exception thrown when an expression refers to an unknown named nested expression.
@ Absolute
Referring to an absolute value.
@ Transfer
Transfers responsibility to the receiving party.
static ALIB_FORCE_INLINE void Destruct(T *object)
Definition alib.cpp:57
lang::Exception Exception
Type alias in namespace alib.
expressions::Expressions EXPRESSIONS
lox::Scope Scope
Type alias in namespace alib.
std::shared_ptr< lang::format::Formatter > SPFormatter
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:286
static ForwardIterator begin()
Definition records.hpp:423
std::vector< ScopeResource *, StdContMA< ScopeResource * > > Resources
Definition scope.hpp:117
MonoAllocator Allocator
Definition scope.hpp:90
HashMap< NString, ScopeResource * > NamedResources
Definition scope.hpp:123
std::vector< alib::Box > Stack
Definition scope.hpp:108
std::vector< Expression *, StdContMA< Expression * > > NestedExpressions
Definition scope.hpp:111
static ALIB_API Box DateTime
static ALIB_API Box Duration
static ALIB_API Box Void
static ALIB_API Box Integer
static ALIB_API Box Boolean
static ALIB_API Box String
static ALIB_API Box Float
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:25
virtual detail::AST * Parse(const String &expressionString, NumberFormat *numberFormat, monomem::MonoAllocator *allocator)=0