ALib C++ Framework
by
Library Version: 2605 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
compiler.cpp
1namespace alib { namespace expressions {
2
3using namespace detail;
4
5//##################################################################################################
6// Scope constructor, Clear()
7//##################################################################################################
8Scope::Scope( SPFormatter& formatter) // evaluation scope constructor using an own allocator
9: EvalScopeAllocator(MonoAllocator::Create(ALIB_DBG("ExpressionScope",) 1, 200))
12, Formatter (formatter)
13, NamedResources (nullptr)
16, DCS ("ExpressionEvalScope")
17#endif
18{}
19
20Scope::Scope( MonoAllocator& allocator, SPFormatter& formatter )
21: EvalScopeAllocator(nullptr) // compile-time scope constructor using the allocator of the expression
22, Allocator (allocator)
24, Formatter (formatter)
26 NString,
28, EvalScopeVMMembers(nullptr)
30, DCS ("ExpressionCTScope")
31#endif
32{}
33
34Scope::~Scope() {
35 // Destruct members in vectors and tables.
38 if ( EvalScopeAllocator ) {
41} }
42
43
44void Scope::freeResources() {
45 Stack->clear();
46
47 if ( NamedResources )
48 for( auto& resource : *NamedResources )
49 lang::Destruct(*resource.second);
50}
51
52void Scope::Reset() {
53 ALIB_ASSERT( !IsCompileTime(), "EXPR" )
54
55 // save sizes
56 auto stackSize= Stack->size();
57 auto nestedExpressionsSize= EvalScopeVMMembers->NestedExpressions.size();
58
59 // free and destruct
63 Allocator.Reset(sizeof(MonoAllocator), alignof(MonoAllocator));
64
65 // create new
68
69 // reserve storage of the previous sizes for the next run.
70 Stack->reserve( stackSize );
71 EvalScopeVMMembers->NestedExpressions.reserve(nestedExpressionsSize );
72}
73
74
75//##################################################################################################
76// Constructor & Setup
77//##################################################################################################
79: allocator (ALIB_DBG("ExpressionCompiler",) 4)
80, typeMap (allocator, 2.0, 5.0) // we don't care about speed here, just for log output
87 // create a clone of the default formatter.
89
90 // register compiler types
91 constexpr std::pair<Box&,NString> typeKeys[]=
92 {
93 { Types::Void , "T_VOID" },
94 { Types::Boolean , "T_BOOL" },
95 { Types::Integer , "T_INT" },
96 { Types::Float , "T_FLOAT" },
97 { Types::String , "T_STR" },
99 { Types::DateTime , "T_DATE" },
100 { Types::Duration , "T_DUR" }, )
101 };
102
103 size_t idx= sizeof( typeKeys ) / sizeof( std::pair<Box&, NString> );
104 do
105 {
106 --idx;
107 auto& name= EXPRESSIONS.GetResource( typeKeys[idx].second );
108 ALIB_STRINGS_TO_NARROW( name, nameNarrow, 128 )
109 AddType( typeKeys[idx].first, nameNarrow );
110 }
111 while( idx != 0 );
112
113 // load nested expression function descriptor
116}
117
118Compiler::~Compiler() { if( Repository != nullptr ) delete Repository; }
119
121{
122 auto* result= ctAllocator().New<Scope>( ctAllocator, CfgFormatter );
123 return result;
124}
125
127 //------------------------------------- add default unary ops ------------------------------------
130 ALIB_ASSERT_ERROR( enumRecordIt.Enum() == DefaultUnaryOperators::NONE, "EXPR",
131 "Expected none-operator as first enum record" )
132 while( ++enumRecordIt != EnumRecords<DefaultUnaryOperators>::end() )
133 AddUnaryOperator( enumRecordIt->EnumElementName );
134
135 // default unary op aliases
137 // Not -> !
139 if( record.Symbol.IsNotEmpty() )
140 AlphabeticUnaryOperatorAliases.EmplaceOrAssign( record.Symbol,
141 record.Replacement );
142 } }
143
144 //------------------------------------- add default binary ops -----------------------------------
147 ALIB_ASSERT_ERROR( enumRecordIt.Enum() == DefaultBinaryOperators::NONE, "EXPR",
148 "Expected none-operator as first enum record" )
149 while( ++enumRecordIt != EnumRecords<DefaultBinaryOperators>::end() ) {
150 // get symbol
151 if ( enumRecordIt->Symbol.Equals<NC>(A_CHAR("[]"))
153 continue;
154
155 // use equal operator's precedence for assign operator, if aliased.
156 auto precedence = ( enumRecordIt.Enum() == DefaultBinaryOperators::Assign
157 && HasBits(CfgCompilation,
160 : enumRecordIt->Precedence;
161
162 AddBinaryOperator(enumRecordIt->Symbol, precedence);
163 }
164
165 // default binary op aliases
168 AlphabeticBinaryOperatorAliases.EmplaceOrAssign( enumEntry.Symbol,
169 enumEntry.Replacement );
170 }
171
172
173 //---------------------------------------- add default plug --------------------------------------
174 CfgNormalizationDisallowed.emplace_back( A_CHAR("--") );
175 CfgNormalizationDisallowed.emplace_back( A_CHAR("++") );
176
179
182
185
188
191
195}
196
197//##################################################################################################
198// Parse and compile
199//##################################################################################################
200Expression Compiler::Compile( const String& expressionString ) {
201 // checks
202 ALIB_ASSERT_ERROR( HasPlugins(), "EXPR",
203 "No plug-ins attached. Invoke SetupDefaults() on compiler instance." )
204 ALIB_ASSERT_ERROR( expressionString.IsNotNull(), "EXPR", "Nulled expression string." )
205 if( expressionString.IsEmpty() )
207
208
209 Expression expression( 1, 100 );
210 expression.ConstructT( expression.GetAllocator(),
211 expressionString,
212 createCompileTimeScope(expression.GetAllocator()) );
213
214 // parser
215 if (parser == nullptr)
216 parser= Parser::Create( *this );
217
218 AST* ast = nullptr;
219
220 // prevent cleaning memory with recursive compilation (may happen with nested expressions)
221 static integer recursionCounter= 0;
222 monomem::Snapshot startOfCompilation;
223 if( recursionCounter++ == 0 )
224 startOfCompilation= allocator.TakeSnapshot();
225
226 try
227 {
228 ALIB_DBG( Ticks startTime; )
229
230 // parse
231 ast= static_cast<AST*>(parser->Parse( expressionString, &CfgFormatter->DefaultNumberFormat ));
232
233 ALIB_DBG(
234 expression->DbgParseTime= startTime.Age();
235 startTime= Ticks::Now();
236 )
237
238 // optimize on AST level
239 ast= ast->Optimize( CfgNormalization );
240
241 // create program
242 expression->program= new detail::Program( *this, *expression, &allocator );
243
244 // assemble
245 ast->Assemble( *static_cast<detail::Program*>(expression->program), allocator,
246 expression->normalizedString );
247 expression->normalizedString.TrimEnd();
248
249 static_cast<detail::Program*>(expression->program)->AssembleFinalize();
250 ALIB_DBG( expression->DbgAssemblyTime= startTime.Age(); )
251
252 if(--recursionCounter == 0)
253 allocator.Reset( startOfCompilation );
254
255 // checks
257 !static_cast<detail::Program*>(expression->program)->ResultType().IsType<void>(),
258 "EXPR", "No exception when parsing expression, but result type is void!" )
259
261 !static_cast<detail::Program*>(expression->program)->ResultType().IsType<void>(),
262 "EXPR", "No exception when parsing expression, but result type is void." )
263 }
264 catch( Exception& )
265 {
266 expression= nullptr;
267 if(--recursionCounter == 0)
268 allocator.Reset( startOfCompilation );
269 throw;
270 }
271 catch( std::exception& )
272 {
273 expression= nullptr;
274 if(--recursionCounter == 0)
275 allocator.Reset( startOfCompilation );
276 throw;
277 }
278
279 // Assert that nobody touches this allocator from now on. With evaluations,
280 // exclusively the evaluation scope is to be used.
281 expression->ctScope->Allocator.DbgLock(true);
282
283 return Expression(expression);
284}
285
287 detail::AST* ast= nullptr;
288 auto startOfDecompilation= allocator.TakeSnapshot();
289 try
290 {
291 expression.allocator.DbgLock(false);
292 ast = detail::VirtualMachine::Decompile( *static_cast<detail::Program*>(expression.program),
293 allocator );
294 detail::Program* program= allocator().New<detail::Program>( *this, expression, nullptr );
295 ast->Assemble( *program, allocator, expression.optimizedString );
296 program->AssembleFinalize();
297 lang::Destruct(*program);
298 expression.allocator.DbgLock(true);
299 }
300 catch(Exception& )
301 {
302 allocator.Reset( startOfDecompilation );
303 throw;
304 }
305 allocator.Reset( startOfDecompilation );
306}
307
308
309//##################################################################################################
310// Manage named expressions
311//##################################################################################################
312
313bool Compiler::AddNamed( const String& name, const String& expressionString ) {
314 String128 key;
316 key << name;
318 key.ToUpper();
319
320 auto it= namedExpressions.Find( key );
321 bool existed= it != namedExpressions.end();
322
323 // removal requested?
324 if( expressionString.IsNull() ) {
325 if ( existed ) {
326 namedExpressions.erase( it );
327 return true;
328 }
329 return false;
330 }
331
332 auto compiledExpression= Compile( expressionString );
333 compiledExpression->allocator.DbgLock(false);
334 compiledExpression->name.Allocate( compiledExpression->allocator, name);
335 compiledExpression->allocator.DbgLock(true);
336 ALIB_ASSERT( compiledExpression, "EXPR" )
337 if( existed )
338 it.Mapped()= compiledExpression;
339 else
340 namedExpressions.EmplaceUnique( key, compiledExpression );
341 return existed;
342}
343
345 // search
346 String128 key;
348 key << name;
350 key.ToUpper();
351
352 auto it= namedExpressions.Find( key );
353 if( it != namedExpressions.end() )
354 return it.Mapped();
355
356 // not found! -> use protected, virtual method to get the string from somewhere
357 AString expressionString;
358 if (Repository == nullptr || !Repository->Get( name, expressionString ) )
360
361 // Got an expression string! -> Compile
362 Expression parsedExpression= Compile( expressionString );
363
364 parsedExpression->allocator.DbgLock(false);
365 parsedExpression->name.Allocate( parsedExpression->allocator, name );
366 parsedExpression->allocator.DbgLock(true);
367
368 Expression sharedExpression( parsedExpression );
369 namedExpressions.EmplaceUnique( key, sharedExpression );
370
371 return sharedExpression;
372}
373
374//##################################################################################################
375// Helpers
376//##################################################################################################
377void Compiler::AddType( Type sample, const NString& name ) {
378 ALIB_DBG( auto it= )
379 typeMap.EmplaceIfNotExistent( &sample.TypeID(), name );
380 ALIB_ASSERT_ERROR( it.second == true, // is insert
381 "EXPR", "Type already registered with compiler." )
382}
383
385 if( box.IsType<void>() )
386 return "NONE";
387
388 auto entry= typeMap.Find( &box.TypeID() );
389 ALIB_ASSERT_WARNING( entry != typeMap.end(), "EXPR",
390 "Custom type \"{}\" not registered. Please use Compiler::AddType to do so.", &box.TypeID() )
391 if( entry == typeMap.end() )
392 return "Unknown Type";
393
394 return entry.Mapped();
395}
396
397void Compiler::WriteFunctionSignature( Box** boxArray, size_t qty, AString& target ) {
398 bool variadic= qty && (*(boxArray + qty -1)) == nullptr;
399 if( variadic )
400 --qty;
401
402 target<< '(';
403 bool isFirst= true;
404 for( size_t i= 0 ; i < qty ; ++i ) {
405 if(!isFirst)
406 target<< ", ";
407 isFirst= false;
408 target << '<' << TypeName( **boxArray++ ) << '>';
409 }
410 if(variadic) {
411 if(!isFirst)
412 target<< ", ";
413 target<< "...";
414 }
415
416 target<< ')';
417}
418
420 ArgIterator end,
421 AString& target ) {
422 std::vector<Box*> buf;
423 buf.reserve( size_t(end - begin) );
424 while( begin != end )
425 buf.emplace_back( &*begin++ );
426 WriteFunctionSignature( buf.data(), buf.size(), target );
427}
428
429
430
431}} // namespace [alib::expressions]
#define ALIB_CALLER_NULLED
#define ALIB_CALLER
#define A_CHAR(STR)
#define ALIB_ASSERT(cond, domain)
#define ALIB_DEBUG_CRITICAL_SECTIONS
#define ALIB_ASSERT_WARNING(cond, domain,...)
#define IF_ALIB_CAMP(...)
#define ALIB_DBG(...)
#define ALIB_ASSERT_ERROR(cond, domain,...)
bool IsType() const
const std::type_info & TypeID() const
Definition box.hpp:759
Normalization CfgNormalization
Definition compiler.hpp:256
ListMA< String > UnaryOperators
Definition compiler.hpp:104
Compilation CfgCompilation
Compilation flags.
Definition compiler.hpp:252
virtual Expression Compile(const String &expressionString)
Definition compiler.cpp:200
NString TypeName(Type box)
Definition compiler.cpp:384
StringVectorMA CfgNormalizationDisallowed
Definition compiler.hpp:277
void WriteFunctionSignature(Box **boxArray, size_t qty, AString &target)
Definition compiler.cpp:397
virtual Expression GetNamed(const String &name)
Definition compiler.cpp:344
BuiltInPlugins CfgBuiltInPlugins
Definition compiler.hpp:218
void AddBinaryOperator(const String &symbol, int precedence)
Definition compiler.hpp:161
strings::util::Token CfgNestedExpressionFunction
Definition compiler.hpp:243
virtual bool AddNamed(const String &name, const String &expressionString)
Definition compiler.cpp:313
ExpressionRepository * Repository
Definition compiler.hpp:300
void getOptimizedExpressionString(ExpressionVal &expression)
Definition compiler.cpp:286
HashMap< MonoAllocator, String, int > BinaryOperators
Definition compiler.hpp:152
void AddUnaryOperator(const String &symbol)
Definition compiler.hpp:133
@ AutoCast
Installs #"plugins::AutoCast;*".
Definition compiler.hpp:197
@ DateAndTime
Installs #"plugins::DateAndTime;*". ).
Definition compiler.hpp:202
@ Arithmetics
Installs #"plugins::Arithmetics;*".
Definition compiler.hpp:198
@ Strings
Installs #"plugins::Strings;*".
Definition compiler.hpp:200
@ Math
Installs #"plugins::Math;*".
Definition compiler.hpp:199
@ ElvisOperator
Installs #"plugins::ElvisOperator;*".
Definition compiler.hpp:196
detail::Parser * parser
The expression parser.
Definition compiler.hpp:73
virtual Scope * createCompileTimeScope(MonoAllocator &expressionAllocator)
Definition compiler.cpp:120
void AddType(Type sample, const NString &name)
Definition compiler.cpp:377
HashMap< MonoAllocator, AString, Expression, std::hash< String >, std::equal_to< String > > namedExpressions
The map of 'named' expressions.
Definition compiler.hpp:85
HashMap< MonoAllocator, String, String, alib::hash_string_ignore_case< character >, alib::equal_to_string_ignore_case< character > > AlphabeticUnaryOperatorAliases
Definition compiler.hpp:115
HashMap< MonoAllocator, lang::TypeFunctors::Key, NAString, lang::TypeFunctors::Hash, lang::TypeFunctors::EqualTo > typeMap
The map of Type names and bit flag values.
Definition compiler.hpp:79
virtual ~Compiler()
Destructor.
Definition compiler.cpp:118
HashMap< MonoAllocator, String, String, alib::hash_string_ignore_case< character >, alib::equal_to_string_ignore_case< character > > AlphabeticBinaryOperatorAliases
Definition compiler.hpp:125
detail::ProgramBase * program
The compiled expression program.
const Box & ResultType() const
Definition program.hpp:148
static SPFormatter DEFAULT
void InsertPlugin(CompilerPlugin *plugin, lang::Responsibility responsibility=lang::Responsibility::KeepWithSender)
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.hpp:236
constexpr bool IsEmpty() const
Definition string.hpp:349
constexpr bool IsNotNull() const
Definition string.hpp:339
constexpr bool IsNull() const
Definition string.hpp:334
const RecordsTraits< TEnum >::Type & GetRecord(TEnum element)
Definition records.hpp:182
@ 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.hpp: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=' ')
Definition alox.cpp:14
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
strings::TString< nchar > NString
Type alias in namespace #"%alib".
Definition string.hpp:2174
containers::SharedPtr< format::Formatter > SPFormatter
Definition formatter.hpp:41
lang::integer integer
Type alias in namespace #"%alib".
Definition integers.hpp:149
boxing::Box Box
Type alias in namespace #"%alib".
Definition box.hpp:1128
enumrecords::EnumRecords< TEnum > EnumRecords
Type alias in namespace #"%alib".
Definition records.hpp:475
containers::HashMap< TAllocator, TKey, TMapped, THash, TEqual, THashCaching, TRecycling > HashMap
Type alias in namespace #"%alib".
strings::TString< character > String
Type alias in namespace #"%alib".
Definition string.hpp:2165
expressions::ExpressionsCamp EXPRESSIONS
The singleton instance of ALib Camp class #"ExpressionsCamp".
exceptions::Exception Exception
Type alias in namespace #"%alib".
expressions::Expression Expression
Type alias in namespace #"%alib".
LocalString< 128 > String128
Type alias name for #"TLocalString;TLocalString<character,128>".
time::Ticks Ticks
Type alias in namespace #"%alib".
Definition ticks.hpp:86
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace #"%alib".
std::vector< T, StdMA< T > > StdVectorMA
Type alias in namespace #"%alib".
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
static ForwardIterator begin()
Definition records.hpp:373
static constexpr ForwardIterator end()
Definition records.hpp:381
Members used by the virtual machine. This is constructed only with evaluation-time scopes.
Definition scope.hpp:64
VMMembers * EvalScopeVMMembers
The members used for the virtual machine. Available only with evaluation-time instances.
Definition scope.hpp:124
StdVectorMA< Box > * Stack
Definition scope.hpp:101
virtual void freeResources()
This method is called in the destructor, as well as in method #"Scope::Reset".
Definition compiler.cpp:44
MonoAllocator & Allocator
Definition scope.hpp:96
HashMap< MonoAllocator, NString, ScopeResource * > * NamedResources
Definition scope.hpp:121
SPFormatter Formatter
Definition scope.hpp:115
lang::DbgCriticalSections DCS
Definition scope.hpp:129
MonoAllocator * EvalScopeAllocator
Definition scope.hpp:88
static Box Integer
Sample type-box for integer types. (Precisely for type #"lang::integer".).
static Box Boolean
Sample type-box for C++ type bool.
static Box Void
Sample type-box for C++ type void.
static Box Float
Sample type-box for C++ type double.
static Box DateTime
Sample type-box for date and time values of type #"time::DateTime").
virtual AST * Optimize(Normalization normalization)=0
virtual void Assemble(Program &program, MonoAllocator &allocator, AString &normalized)=0
static Parser * Create(Compiler &compiler)
Definition parser.cpp:4
static AST * Decompile(Program &program, MonoAllocator &allocator)