ALib C++ Framework
by
Library Version: 2605 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
program.cpp
1namespace alib { namespace expressions { namespace detail {
2
3//! @cond NO_DOX
4using Command= VirtualMachine::Command;
5//! @endcond
6
7//##################################################################################################
8// Program
9//##################################################################################################
10
11#if ALIB_DEBUG
12# define DBG_SET_CALLBACK_INFO \
13 prg.act().DbgInfo.Callback= cInfo.DbgCallbackName; \
14 prg.act().DbgInfo.Plugin = ppp.plugin;
15#else
16# define DBG_SET_CALLBACK_INFO
17#endif
18
19// Use temporary allocator for program vector construction.
20// In method AssembleFinalize, this will be re-allocated into ctScope
21Program::Program( Compiler& pCompiler, ExpressionVal& pExpression, MonoAllocator* ctAlloc )
22: compiler ( pCompiler )
23, expression ( pExpression )
25, qtyOptimizations ( HasBits( compiler.CfgCompilation, Compilation::NoOptimization )
26 ? -1 : 0 )
27, compileStorage ( ctAlloc ? (*ctAlloc)().New<CompileStorage>(*ctAlloc) : nullptr ) {}
28
30
31
32//##################################################################################################
33// Helpers used during compilation
34//##################################################################################################
35#if !DOXYGEN
36namespace {
37struct Assembly {
38 using VM= VirtualMachine;
39
41 StdVectorMA<VM::PC >& resultStack;
42
43 Assembly( StdVectorMA<VirtualMachine::Command*>& pAssembly,
44 StdVectorMA<VM::PC >& pResultStack )
45 : assembly ( pAssembly )
46 , resultStack( pResultStack) {}
47
48 /// Returns the current last command.
49 /// @return A reference to the last command.
50 integer length() { return integer(assembly.size()); }
51
52 /// Returns the command at the given program counter \p{pc}.
53 /// @param pc The program counter of the command to get.
54 /// @return A reference to the requested command.
55 VM::Command& at( VM::PC pc ) { return *assembly[size_t(pc)]; }
56
57 /// Returns the current last command.
58 /// @return A reference to the last command.
59 VM::Command& act() { return *assembly.back(); }
60
61 /// Returns the current last command.
62 /// @return A reference to the last command.
63 VM::Command& prev() { return **( assembly.end() - 2 ); }
64
65 /// Returns the number of the last command.
66 /// @return The current size of the program minus \c 1.
67 VM::PC actPC() { return static_cast<VM::PC>( assembly.size() - 1); }
68
69 /// Removes the last command.
70 void eraseLast() { assembly.pop_back(); }
71
72 /// Removes a command.
73 /// @param pc The command to remove.
74 void erase( VM::PC pc ) { assembly.erase( assembly.begin() + pc ); }
75
76 /// Removes range of commands.
77 /// @param begin The first command to remove.
78 /// @param end The first command that is not removed.
79 void erase( VM::PC begin, VM::PC end )
80 {
81 assembly.erase( assembly.begin() + begin,
82 assembly.begin() + end );
83 }
84
85
86 /// Inserts a command at the given position.
87 /// @tparam TArgs Types of the variadic arguments \p{args}.
88 /// @param pc The position of insertion.
89 /// @param args Variadic arguments forwarded to the command's constructor.
90 /// @return The command inserted.
91 template<typename... TArgs>
92 VM::Command& insertAt( VM::PC pc, TArgs && ... args ) {
93 auto* cmd= assembly.get_allocator().AIF().New<VM::Command>(std::forward<TArgs>( args )... );
94 assembly.emplace( assembly.begin() + pc, cmd );
95 return *cmd;
96 }
97
98 /// Inserts a command at the end of the program.
99 /// @tparam TArgs Types of the variadic arguments \p{args}.
100 /// @param args Variadic arguments forwarded to the command's constructor.
101 /// @return The command inserted.
102 template<typename... TArgs>
103 VM::Command& add( TArgs && ... args ) {
104 assembly.emplace_back(
105 assembly.get_allocator().AIF().New<VM::Command>( std::forward<TArgs>( args )... ) );
106 return *assembly.back();
107 }
108
109
110 /// Pushes the current PC to the result stack.
111 void pushResultPC() { resultStack.push_back( actPC() ); }
112
113 /// Pops one from the result stack.
114 void popResultPC() { resultStack.pop_back(); }
115
116 /// Returns a mutable reference to the top of the stack of result positions.
117 VM::PC & resultPC() { return resultStack.back(); }
118
119 /// Returns a mutable reference to the 2nd.-top of the stack of result positions.
120 VM::PC & lhsResultPC() { return resultStack[resultStack.size() - 2]; }
121
122 /// Returns the program counter that identifies the start of the range that results in the
123 /// current LHS value.
124 VM::PC lhsResultStartPC() {
125 auto qtyResults = resultStack.size();
126 return qtyResults == 2 ? 0
127 : resultStack[qtyResults - 3] + 1; // one after the previous
128 }
129};
130} // anonymous namespace
131#endif // DOXYGEN
132
133//##################################################################################################
134// Assemble commands
135//##################################################################################################
136
137#define ASSERT_ASSEMBLE \
138 ALIB_ASSERT_ERROR( prg.resultStack.empty() \
139 || prg.resultPC() == prg.actPC() \
140 || prg.act().IsJump() , \
141 "EXPR", "Internal error: Last in result stack is not last command." )
142
145 ALIB_ASSERT_ERROR( compileStorage->ResultStack.size() >= size_t( qty < 0 ? 0 : qty ),
146 "EXPR", "Internal error. This should never happen." ) // not enough arguments on the stack
147
148 stack->clear();
149 if( qty > 0 )
150 stack->reserve( size_t( qty ));
151
152 bool allAreConst= true;
153 for( integer i= qty; i > 0 ; --i ) {
154 Command& cmd= *compileStorage->Assembly[size_t(*(compileStorage->ResultStack.end() - i))];
155 bool isConstant= cmd.IsConstant();
156 stack->emplace_back( cmd.ResultType );
157 allAreConst&= isConstant;
158 }
159
160 return allAreConst && !HasBits(compiler.CfgCompilation, Compilation::NoOptimization );
161}
162
163
164void Program::AssembleConstant( Box& value, integer idxInOriginal, integer idxInNormalized ) {
165 if( compileStorage == nullptr )
166 return;
167 Assembly prg( compileStorage->Assembly, compileStorage->ResultStack);
168 ASSERT_ASSEMBLE
169
171 value.Unbox<String>() )
172 : value,
173 false, idxInOriginal, idxInNormalized ) );
174 prg.pushResultPC();
175}
176
177
178void Program::AssembleFunction( AString& functionName , bool isIdentifier, int qtyArgs,
179 integer idxInOriginal, integer idxInNormalized ) {
180 if( compileStorage == nullptr )
181 return;
182 Assembly prg( compileStorage->Assembly, compileStorage->ResultStack);
183 ASSERT_ASSEMBLE
184
185 // Nested expressions
186 if( compiler.CfgNestedExpressionFunction.GetDefinitionName().IsNotEmpty()
187 && compiler.CfgNestedExpressionFunction.Match(functionName ) )
188 {
189 functionName.Reset( compiler.CfgNestedExpressionFunction );
190
191 if( qtyArgs < (HasBits( compiler.CfgCompilation, Compilation::AllowCompileTimeNestedExpressions )
192 ? 1 : 2 )
193 || !prg.at( *(prg.resultStack.end() - ( qtyArgs == 3 ? 2 : qtyArgs) ) )
194 .ResultType.IsType<String>() )
195 {
197 compiler.CfgNestedExpressionFunction );
198 }
199
200
201 // single argument? -> we have to get the expression now
202 if( qtyArgs == 1 ) {
203 if( !prg.at(compileStorage->ResultStack.back()).IsConstant() ) { // must not use bool allAreConstant here!
206 expression.GetOriginalString(), idxInOriginal );
207 throw e;
208 }
209
210 Expression nested;
211 String nestedExpressionName= prg.at(prg.resultStack.back()).ResultType.Unbox<String>();
212 try
213 {
214 nested= compiler.GetNamed( nestedExpressionName );
215 }
216 catch( Exception& e )
217 {
220 nestedExpressionName );
221 } else {
222 ALIB_ERROR( "EXPR", "Unknown exception \"{}\".", e.Type() )
223 }
224 throw;
225 }
226
227 ctNestedExpressions.emplace_back(nested);
228
229 prg.act()= VM::Command( static_cast<detail::Program*>(nested->GetProgram()),
230 nested->ResultType(),
231 compiler.CfgNestedExpressionFunction.GetDefinitionName(),
232 idxInOriginal, idxInNormalized );
233 return;
234 }
235
236 // If two arguments, we send nullptr to indicate that 2nd argument is replacement
237 if( qtyArgs == 2 ) {
238 prg.add( static_cast<Program*>( nullptr ), Box( nullptr ),
239 compiler.CfgNestedExpressionFunction.GetDefinitionName(),
240 idxInOriginal, idxInNormalized );
241 prg.act().ResultType= prg.prev().ResultType;
242 }
243
244 // 3rd argument given (throw): we send "this" which indicates to throw if an
245 // expression is not found.
246 else
247 prg.add( dynamic_cast<Program*>( this ),
248 prg.act().ResultType,
249 compiler.CfgNestedExpressionFunction.GetDefinitionName(),
250 idxInOriginal, idxInNormalized );
251
252 prg.popResultPC();
253 prg.resultPC()= prg.actPC();
254 return;
255 }
256
257
258 // collect arguments
259 bool allAreConstant= collectArgs(qtyArgs);
260
261 compileStorage->FunctionsWithNonMatchingArguments.Clear();
263 compileStorage->ConditionalStack.get_allocator().GetAllocator(),
264 functionName, isIdentifier,
265 allAreConstant,
266 compileStorage->FunctionsWithNonMatchingArguments );
267
268 try
269 {
270 for( auto& ppp : getCompilerPlugins(compiler) ) {
271 if( !ppp.plugin->TryCompilation( cInfo ) )
272 continue;
273
274 // constant?
275 if( cInfo.Callback == nullptr ) {
276 if( qtyArgs > 0 )
278
279 // remove constant vm commands, add new and update result stack
280 if( getExpressionCTScope(expression)->Stack->size() == 0 ) {
281 prg.add( VM::Command( cInfo.TypeOrValue, true, idxInOriginal, idxInNormalized ) );
282 prg.pushResultPC();
283 } else {
284 for( size_t i= getExpressionCTScope(expression)->Stack->size() - 1; i > 0 ; --i ) {
285 prg.eraseLast();
286 prg.popResultPC();
287 }
288 prg.resultPC()= prg.actPC();
289 prg.act()= VM::Command( cInfo.TypeOrValue, true, idxInOriginal, idxInNormalized );
290 }
291
292 DBG_SET_CALLBACK_INFO
293
294 return;
295 }
296
297 // function
298 prg.add( cInfo.Callback, isIdentifier, qtyArgs, cInfo.TypeOrValue,
299 String(getExpressionAllocator(expression), functionName), false,
300 idxInOriginal, idxInNormalized );
301
302 // update result type stack
303 if( getExpressionCTScope(expression)->Stack->size()== 0 )
304 prg.pushResultPC();
305 else {
306 for( size_t i= getExpressionCTScope(expression)->Stack->size() - 1; i > 0 ; --i )
307 prg.popResultPC();
308 prg.resultPC()= prg.actPC();
309 }
310
311 DBG_SET_CALLBACK_INFO
312 return;
313 } }
314 catch( Exception& e )
315 {
316 if( !HasBits(compiler.CfgCompilation, Compilation::PluginExceptionFallThrough)
317 && !e.Type().IsEnumType<Exceptions>() )
319
320 e.Add ( ALIB_CALLER_NULLED, Exceptions::ExpressionInfo, expression.GetOriginalString(), idxInOriginal );
321 throw;
322 }
323 catch( std::exception& stdException )
324 {
325 if( !HasBits(compiler.CfgCompilation, Compilation::PluginExceptionFallThrough) ) {
328 expression.GetOriginalString(), idxInOriginal );
329 e.Add ( ALIB_CALLER_NULLED, Exceptions::StdExceptionInfo, stdException.what() );
330 throw e;
331 }
332 throw;
333 }
334
335
336 // create identifier exception
337 if( isIdentifier )
339
340 // create function exception
341 String128 arguments;
343 compiler.WriteFunctionSignature( getExpressionCTScope(expression)->Stack->begin(),
344 getExpressionCTScope(expression)->Stack->end(), arguments );
345
346 Exception e( ALIB_CALLER_NULLED, Exceptions::UnknownFunction, functionName, arguments );
347
348 for( auto& notMatchedName : cInfo.FunctionsWithNonMatchingArguments )
349 e.Add( ALIB_CALLER_NULLED, Exceptions::FunctionHint, notMatchedName );
350
351 throw e;
352}
353
354void Program::AssembleUnaryOp( String& op, integer idxInOriginal, integer idxInNormalized ) {
355 if( compileStorage == nullptr )
356 return;
357 Assembly prg( compileStorage->Assembly, compileStorage->ResultStack);
358 ASSERT_ASSEMBLE
359
360 // If we have a global operator replacement, this will be used. However, in this case changes
361 // of it must not be passed back to the caller as long certain normalization flags are set.
362 String opReference= op;
363 bool aliased= false;
364 auto globalAliasIt= compiler.AlphabeticUnaryOperatorAliases.Find(op);
365 if( globalAliasIt != compiler.AlphabeticUnaryOperatorAliases.end() ) {
366 aliased= true;
367 opReference= globalAliasIt.Mapped();
368 }
369
370 bool isConstant= collectArgs(1);
371
372 // Nested expressions
373 if( HasBits( compiler.CfgCompilation, Compilation::AllowCompileTimeNestedExpressions )
374 && opReference == compiler.CfgNestedExpressionOperator
375 && getExpressionCTScope(expression)->Stack->back().IsType<String>() )
376 {
377 if( !prg.at(compileStorage->ResultStack.back()).IsConstant() ) { // must not use bool allAreConstant here!
380 expression.GetOriginalString(), idxInOriginal );
381 throw e;
382 }
383
384 String expressionName= getExpressionCTScope(expression)->Stack->back().Unbox<String>();
385 Expression nested;
386 try
387 {
388 nested= compiler.GetNamed( expressionName );
389 }
390 catch( Exception& e )
391 {
394 expressionName );
395 else {
396 ALIB_ERROR( "EXPR", "Unknown exception \"{}\".", e.Type() )
397 }
398 throw;
399 }
400
401 if( !aliased || HasBits(compiler.CfgNormalization, Normalization::ReplaceVerbalOperatorsToSymbolic ) )
402 op= opReference;
403 else
405 op= globalAliasIt->first;
406
407 ctNestedExpressions.emplace_back(nested);
408 prg.act()= VM::Command( static_cast<detail::Program*>(nested->GetProgram()),
409 nested->ResultType(),
410 op,
411 idxInOriginal, idxInNormalized );
412 return;
413 }
414
415
416 try
417 {
418 for( int pass= 0; pass < 2 ; ++pass ) {
419 isConstant= collectArgs(1);
421 compileStorage->ConditionalStack.get_allocator().GetAllocator(),
422 opReference, isConstant );
423
424 // search plug-ins
425 for( auto& ppp : getCompilerPlugins(compiler) ) {
426 if( !ppp.plugin->TryCompilation( cInfo ) )
427 continue;
428
429 if( !aliased || HasBits(compiler.CfgNormalization, Normalization::ReplaceVerbalOperatorsToSymbolic ) )
430 op= opReference;
431 else
433 op= globalAliasIt->first;
434
435 // constant?
436 if( !cInfo.Callback ) {
438
439 // replace last command (unary op arg is always the last)
440 prg.act()= VM::Command( cInfo.TypeOrValue, true, idxInOriginal, idxInNormalized );
441
442 DBG_SET_CALLBACK_INFO
443
444 return;
445 }
446
447 // callback
448 prg.add( cInfo.Callback, false, 1, cInfo.TypeOrValue, op, true, idxInOriginal, idxInNormalized );
449 ++prg.resultPC();
450
451 DBG_SET_CALLBACK_INFO
452 return;
453 }
454
455 // did we try auto cast already?
456 if( pass )
457 break;
458
459 // try auto cast
461 compileStorage->ConditionalStack.get_allocator().GetAllocator(),
462 op,
463 prg.at( prg.resultPC() ).IsConstant(), false );
464 for( auto& pppAutoCast : getCompilerPlugins(compiler) ) {
465 if( !pppAutoCast.plugin->TryCompilation( ciAutoCast ) )
466 continue;
467
468 // cast found?
469 if( !ciAutoCast.TypeOrValue.IsType<void>() ) {
470 // const?
471 if( ciAutoCast.Callback == nullptr ) {
472 // change constant value conversion
473 VM::Command& cmdToPatch= prg.at(prg.resultPC());
474 cmdToPatch.ResultType= ciAutoCast.TypeOrValue;
475 ALIB_DBG( cmdToPatch.DbgInfo.Plugin= pppAutoCast.plugin; )
476 }
477
478 // non-const
479 else {
480 // insert conversion
481 ALIB_DBG( auto& newCmd= )
482 prg.insertAt( prg.resultPC() + 1, ciAutoCast.Callback, false, 1,
483 ciAutoCast.TypeOrValue,
484 ciAutoCast.ReverseCastFunctionName, false,
485 idxInOriginal, idxInNormalized );
486
487 ++prg.resultPC();
488 ALIB_DBG( newCmd.DbgInfo.Callback= ciAutoCast.DbgCallbackName;
489 newCmd.DbgInfo.Plugin = pppAutoCast.plugin; )
490 } }
491
492 break;
493
494 } // auto cast plug-in loop
495 } // pass loop
496
497 }
498 catch( Exception& e )
499 {
500 if( !HasBits(compiler.CfgCompilation, Compilation::PluginExceptionFallThrough)
501 && !e.Type().IsEnumType<Exceptions>() )
503 e.Add ( ALIB_CALLER_NULLED, Exceptions::ExpressionInfo, expression.GetOriginalString(), idxInOriginal );
504 throw;
505 }
506 catch( std::exception& stdException )
507 {
508 if( !HasBits(compiler.CfgCompilation, Compilation::PluginExceptionFallThrough) ) {
510 e.Add ( ALIB_CALLER_NULLED, Exceptions::ExpressionInfo, expression.GetOriginalString(), idxInOriginal );
511 e.Add ( ALIB_CALLER_NULLED, Exceptions::StdExceptionInfo, stdException.what() );
512 throw e;
513 }
514 throw;
515 }
516
517
518 // not found
520 e.Add ( ALIB_CALLER_NULLED, Exceptions::ExpressionInfo, expression.GetOriginalString(), idxInOriginal );
521 throw e;
522}
523
524
525void Program::AssembleBinaryOp( String& op, integer idxInOriginal, integer idxInNormalized ) {
526 if( compileStorage == nullptr )
527 return;
528 Assembly prg( compileStorage->Assembly, compileStorage->ResultStack);
529 ASSERT_ASSEMBLE
530
531 // If we have a global operator replacement, this will be used. However, in this case changes
532 // of it must not be passed back to the caller as long certain normalization flags are set.
533 String opReference= op;
534 bool aliased= false;
535 auto globalAliasIt= compiler.AlphabeticBinaryOperatorAliases.Find(op);
536 if( globalAliasIt != compiler.AlphabeticBinaryOperatorAliases.end() ) {
537 aliased= true;
538 opReference= globalAliasIt.Mapped();
539 }
540
541 bool foundOperator= false; // die Variable kann wohl raus. Stattdessen dort wo sie gesetzt wird ein "return" machen.
542 bool triedToAutoCast= false;
543
544 Box lhsOrigType= prg.at(prg.lhsResultPC()).ResultType;
545 Box rhsOrigType= prg.at(prg. resultPC()).ResultType;
546
547
548 for(;;) {
549 collectArgs(2);
550 bool lhsIsConstant= prg.at(prg.lhsResultPC()).IsConstant() && !HasBits(compiler.CfgCompilation, Compilation::NoOptimization );
551 bool rhsIsConstant= prg.at(prg. resultPC()).IsConstant() && !HasBits(compiler.CfgCompilation, Compilation::NoOptimization );
552
554 compileStorage->ConditionalStack.get_allocator().GetAllocator(),
555 opReference, lhsIsConstant, rhsIsConstant );
556
557 try
558 {
559 for( auto& ppp : getCompilerPlugins(compiler) ) {
560 if( !ppp.plugin->TryCompilation( cInfo ) )
561 continue;
562
563 if( !aliased || HasBits(compiler.CfgNormalization, Normalization::ReplaceVerbalOperatorsToSymbolic ) )
564 op= opReference;
565 else
567 op= globalAliasIt->first;
568
569
570 // --- identity? (like "a * 1" or "x && true") ---
571 if( cInfo.NonConstArgIsResult ) {
573
574 // lhs or rhs to remove?
575 if( lhsIsConstant )
576 prg.erase( prg.lhsResultStartPC() );
577 else
578 prg.eraseLast();
579
580 prg.popResultPC();
581 prg.resultPC()= prg.actPC();
582
583 foundOperator= true;
584 break;
585 }
586
587 // --- constant? ---
588 if( cInfo.Callback == nullptr ) {
590
591 // remove lhs, rhs and correct result stack
592 prg.erase( prg.lhsResultStartPC(), prg.resultPC() );
593
594 prg.popResultPC();
595 prg.resultPC()= prg.actPC();
596 prg.act()= VM::Command( cInfo.TypeOrValue, true, idxInOriginal, idxInNormalized );
597
598 foundOperator= true;
599 break;
600 }
601
602 //--- Callback ---
603
604 // found the correct result type stack
605 prg.popResultPC();
606 prg.add( cInfo.Callback, false, 2, cInfo.TypeOrValue, op, true, idxInOriginal, idxInNormalized );
607 prg.resultPC()= prg.actPC();
608
609 DBG_SET_CALLBACK_INFO
610
611 // done!
612 foundOperator= true;
613 break;
614 }
615
616 // success
617 if( foundOperator )
618 return;
619
620 if( !foundOperator && triedToAutoCast ) {
622 op,
623 compiler.TypeName( lhsOrigType ),
624 compiler.TypeName( rhsOrigType ) );
625
626 throw e;
627 }
628
629 // try auto cast (we do this even if types are equal )
630 triedToAutoCast= true;
632 compileStorage->ConditionalStack.get_allocator().GetAllocator(),
633 op,
634 prg.at( prg.lhsResultPC() ).IsConstant(),
635 prg.at( prg. resultPC() ).IsConstant() );
636
637 for( auto& pppAutoCast : getCompilerPlugins(compiler) ) {
638 if( !pppAutoCast.plugin->TryCompilation( ciAutoCast ) )
639 continue;
640
641 // cast for lhs?
642 if( !ciAutoCast.TypeOrValue.IsType<void>() ) {
643 // const?
644 if( ciAutoCast.Callback == nullptr ) {
645 // change constant value conversion
646 VM::Command& cmdToPatch= prg.at( prg.lhsResultPC() );
647 cmdToPatch.ResultType= ciAutoCast.TypeOrValue;
648 ALIB_DBG( cmdToPatch.DbgInfo.Plugin= pppAutoCast.plugin; )
649 }
650
651 // cast function upgrade for lhs?
652 else {
653 // insert conversion
654 ALIB_DBG( auto& newCmd= )
655 prg.insertAt( prg.lhsResultPC() + 1, ciAutoCast.Callback, false, 1,
656 ciAutoCast.TypeOrValue,
657 ciAutoCast.ReverseCastFunctionName, false,
658 idxInOriginal, idxInNormalized );
659
660 ++prg.lhsResultPC();
661 ++prg.resultPC();
662 ALIB_DBG( newCmd.DbgInfo.Callback= ciAutoCast.DbgCallbackName;
663 newCmd.DbgInfo.Plugin= pppAutoCast.plugin; )
664 } }
665
666 // cast for rhs?
667 if( !ciAutoCast.TypeOrValueRhs.IsType<void>() ) {
668 // const?
669 if( ciAutoCast.CallbackRhs == nullptr ) {
670 // change constant value conversion
671 prg.act().ResultType= ciAutoCast.TypeOrValueRhs;
672 ALIB_DBG( prg.act().DbgInfo.Plugin= pppAutoCast.plugin; )
673 }
674
675 // cast function upgrade for rhs?
676 else {
677 // insert conversion
678 ALIB_DBG( auto& newCmd= )
679 prg.insertAt( prg.resultPC() + 1, ciAutoCast.CallbackRhs, false, 1,
680 ciAutoCast.TypeOrValueRhs,
681 ciAutoCast.ReverseCastFunctionNameRhs, false,
682 idxInOriginal, idxInNormalized );
683 ++prg.resultPC();
684
685 ALIB_DBG( newCmd.DbgInfo.Callback= ciAutoCast.DbgCallbackNameRhs;
686 newCmd.DbgInfo.Plugin= pppAutoCast.plugin; )
687 } }
688 break;
689
690 } // auto cast plug-in loop
691 }
692 catch( Exception& e )
693 {
694 if( !HasBits(compiler.CfgCompilation, Compilation::PluginExceptionFallThrough)
695 && !e.Type().IsEnumType<Exceptions>() )
697 e.Add ( ALIB_CALLER_NULLED, Exceptions::ExpressionInfo, expression.GetOriginalString(), idxInOriginal );
698 throw;
699 }
700 catch( std::exception& stdException )
701 {
702 if( !HasBits(compiler.CfgCompilation, Compilation::PluginExceptionFallThrough) ) {
704 e.Add ( ALIB_CALLER_NULLED, Exceptions::ExpressionInfo , expression.GetOriginalString(), idxInOriginal );
705 e.Add ( ALIB_CALLER_NULLED, Exceptions::StdExceptionInfo , stdException.what() );
706 throw e;
707 }
708 throw;
709 }
710
711 } // formally endless loop (max 2)
712}
713
714
715void Program::AssembleCondFinalize_Q( integer idxInOriginal, integer idxInNormalized ) {
716 if( compileStorage == nullptr )
717 return;
718 Assembly prg( compileStorage->Assembly, compileStorage->ResultStack);
719 ASSERT_ASSEMBLE
720
721 // Note:
722 // The "conditional stack" of tuples stores for each nested condition, three values:
723 // 1. The position of the lhs result,
724 // 2. The position of the jump command between T and F
725 // 3. An integer with two bits: bit 1 tells us whether Q was constant and bit 0 which value
726 // the constant Q had. "Had" because it is removed right away.
727
728 // Q constant?
729 int constQ= 0;
730 if( prg.act().IsConstant() && !HasBits(compiler.CfgCompilation, Compilation::NoOptimization ) ) {
732
733 Box& condition= prg.act().ResultType;
734 constQ= 2 + ( condition.Call<FIsTrue>() ? 1 : 0 );
735 prg.eraseLast(); // remove constant Q
736 }
737
738 // insert Q-Jump
739 prg.add( idxInOriginal, idxInNormalized, Command::JumpType::Conditional );
740 compileStorage->ConditionalStack.emplace_back( prg.actPC(), 0, constQ );
741}
742
743
744void Program::AssembleCondFinalize_T( integer idxInOriginal, integer idxInNormalized ) {
745 if( compileStorage == nullptr )
746 return;
747
748 Assembly prg( compileStorage->Assembly, compileStorage->ResultStack);
749 ASSERT_ASSEMBLE
750
751 // insert T-Jump
752 prg.add( idxInOriginal, idxInNormalized, Command::JumpType::Unconditional );
753 ++prg.resultPC(); // for the time being this points to the jump command.
754 // Otherwise upcoming F optimizations don't know where to find the start of F!
755
756 auto& actCond= compileStorage->ConditionalStack.back();
757
758 // patch Q-Jump to command after T-Jump
759 prg.at(actCond.QJumpPos).Parameter.Distance= prg.length() - actCond.QJumpPos;
760
761 // store T-Jump address on conditional stack
762 actCond.TJumpPos= prg.actPC();
763}
764
765void Program::AssembleCondFinalize_F( integer idxInOriginal, integer idxInNormalized ) {
766 if( compileStorage == nullptr )
767 return;
768
769 Assembly prg( compileStorage->Assembly, compileStorage->ResultStack);
770 ASSERT_ASSEMBLE
771
772 auto& actCond= compileStorage->ConditionalStack.back();
773
774 // patch result stack position of T one back (in Finalize_T we had increased it by one to
775 // point to the jump command, to protect it from being deleted with an lhs-delete
776 --prg.lhsResultPC();
777
778 prg.at( actCond.TJumpPos ).Parameter.Distance= prg.length() - actCond.TJumpPos;
779
780
781 // needs type alignment?
782 if( !prg.at( prg.lhsResultPC() ).ResultType.IsSameType( prg.at( prg.resultPC() ).ResultType ) ) {
783 collectArgs(2);
784 String condOp= A_CHAR("Q?T:F");
786 compileStorage->ConditionalStack.get_allocator().GetAllocator(),
787 condOp,
788 prg.at( prg.lhsResultPC() ).IsConstant(),
789 prg.at( prg. resultPC() ).IsConstant() );
790 bool found= false;
791 try
792 {
793 for( auto& ppp : getCompilerPlugins(compiler) )
794 if( ppp.plugin->TryCompilation( ciAutoCast ) ) {
795 if( !ciAutoCast.TypeOrValue.IsType<void>() ) {
796 // const cast upgrade for T?
797 if( ciAutoCast.Callback == nullptr ) {
798 // change constant value conversion and patch type in jump command
799 prg.at(prg.lhsResultPC()).ResultType = ciAutoCast.TypeOrValue;
800
801 ALIB_DBG( prg.at(prg.lhsResultPC()).DbgInfo.Plugin= ppp.plugin; )
802 }
803
804 // upgrade function for T?
805 else if( ciAutoCast.Callback ) {
806 // jump one more (the other as well)
807 ++prg.at(actCond.QJumpPos).Parameter.Distance;
808 ++prg.at(actCond.TJumpPos).Parameter.Distance;
809
810 // insert conversion
811 ALIB_DBG( auto& newCmd= )
812 prg.insertAt( actCond.TJumpPos++, ciAutoCast.Callback, false, 1,
813 ciAutoCast.TypeOrValue,
814 ciAutoCast.ReverseCastFunctionName,
815 false,
816 idxInOriginal, idxInNormalized );
817 ALIB_DBG( newCmd.DbgInfo.Callback= ciAutoCast.DbgCallbackName;
818 newCmd.DbgInfo.Plugin= ppp.plugin; )
819 ++prg.lhsResultPC();
820 } }
821
822 // const cast upgrade for F?
823 if( !ciAutoCast.TypeOrValueRhs.IsType<void>() ) {
824 if( ciAutoCast.Callback == nullptr ) {
825 // change constant value
826 prg.act().ResultType = ciAutoCast.TypeOrValueRhs;
827
828 ALIB_DBG( prg.act().DbgInfo.Callback= ciAutoCast.DbgCallbackNameRhs;
829 prg.act().DbgInfo.Plugin= ppp.plugin; )
830 }
831
832 // upgrade function for T?
833 else {
834 // insert conversion
835 prg.add( ciAutoCast.CallbackRhs, false, 1,
836 ciAutoCast.TypeOrValueRhs,
837 ciAutoCast.ReverseCastFunctionNameRhs, false,
838 idxInOriginal, idxInNormalized );
839 ++prg.resultPC();
840 ++prg.at(actCond.TJumpPos).Parameter.Distance;
841
842 ALIB_DBG( prg.act().DbgInfo.Callback= ciAutoCast.DbgCallbackNameRhs;
843 prg.act().DbgInfo.Plugin= ppp.plugin; )
844 } }
845
846 found= true;
847 break;
848 } }
849 catch( Exception& e )
850 {
851 if( !HasBits(compiler.CfgCompilation, Compilation::PluginExceptionFallThrough)
852 && !e.Type().IsEnumType<Exceptions>() )
854 e.Add ( ALIB_CALLER_NULLED, Exceptions::ExpressionInfo, expression.GetOriginalString(), idxInOriginal );
855 throw;
856 }
857 catch( std::exception& stdException )
858 {
859 if( !HasBits(compiler.CfgCompilation, Compilation::PluginExceptionFallThrough) ) {
861 e.Add ( ALIB_CALLER_NULLED, Exceptions::ExpressionInfo, expression.GetOriginalString(), idxInOriginal );
862 e.Add ( ALIB_CALLER_NULLED, Exceptions::StdExceptionInfo, stdException.what() );
863 throw e;
864 }
865 throw;
866 }
867
868
869 if(!found) {
871 compiler.TypeName( * ciAutoCast.ArgsBegin ),
872 compiler.TypeName( *(ciAutoCast.ArgsBegin+1)) );
873 e.Add ( ALIB_CALLER_NULLED, Exceptions::ExpressionInfo, expression.GetOriginalString(), idxInOriginal );
874
875 throw e;
876 } }
877
878 // was this a constant conditional to be optimized out?
879 if( actCond.ConstFlags ) {
880 // eliminate T?
881 if( (actCond.ConstFlags & 1) == 0 ) {
882 prg.erase( actCond.QJumpPos, actCond.TJumpPos + 1 );
883 }
884
885 // eliminate F?
886 else {
887 prg.erase( actCond.TJumpPos, prg.actPC() + 1 );
888 prg.erase( actCond.QJumpPos );
889 } }
890 else
891 // mark last command as part of conditional. Otherwise constant F-terms become optimized
892 prg.act().SetEndOfConditionalFlag();
893
894
895 // clean the conditional stack
896 compileStorage->ConditionalStack.pop_back();
897
898 // remove results Q [? T : F]
899 prg.popResultPC();
900 prg.popResultPC();
901 prg.resultPC()= prg.actPC();
902}
903
904
906 if( compileStorage == nullptr )
907 return;
908
909 ALIB_DBG(Assembly prg( compileStorage->Assembly, compileStorage->ResultStack); )
910 ASSERT_ASSEMBLE
911
912 ALIB_ASSERT_ERROR( compileStorage->ConditionalStack.size() == 0, "EXPR",
913 "Finalizing program, while conditional stack is of size {}.",
914 compileStorage->ConditionalStack.size() )
915 ALIB_ASSERT_ERROR( compileStorage->ResultStack.size() == 1, "EXPR",
916 "Finalizing program, while result stack is of size {}.",
917 compileStorage->ResultStack.size() )
918
919
920 // copy the program from the temporary vector to a simple array, allocated with the
921 // compile-time scope's allocator.
922 commandsCount= integer( compileStorage->Assembly.size() );
923 commands= getExpressionAllocator(expression)().AllocArray<VM::Command>(compileStorage->Assembly.size() );
924 auto* cmd= commands;
925 for( auto* it : compileStorage->Assembly )
926 new ( cmd++ ) VM::Command(*it);
927
928 compileStorage= nullptr;
929}
930
931#undef ASSERT_ASSEMBLE
932#undef DBG_SET_CALLBACK_INFO
933
934}}} // namespace [alib::expressions::detail]
#define ALIB_CALLER_NULLED
#define A_CHAR(STR)
#define ALIB_ERROR(domain,...)
#define ALIB_DBG(...)
#define ALIB_ASSERT_ERROR(cond, domain,...)
decltype(std::declval< typename TFDecl::Signature >()(std::declval< Box & >(), std::declval< TArgs >()...)) Call(TArgs &&... args) const
Definition box.hpp:964
bool IsType() const
Exception & Add(const lang::CallerInfo &ci, TEnum type, TArgs &&... args)
const Enum & Type() const
Definition exception.cpp:92
Scope * getExpressionCTScope(ExpressionVal &ev)
Definition compiler.hpp:511
MonoAllocator & getExpressionAllocator(ExpressionVal &ev)
Definition compiler.hpp:506
Compiler::PluginList & getCompilerPlugins(Compiler &cmp)
Definition compiler.hpp:516
ExpressionVal & expression
The expression that this program evaluates.
Definition program.hpp:32
const Box & ResultType() const
Definition program.hpp:148
void AssembleUnaryOp(String &op, integer idxInOriginal, integer idxInNormalized)
Definition program.cpp:354
int qtyOptimizations
Counter of the number of optimization made during program assembly.
Definition program.hpp:53
void AssembleFunction(AString &functionName, bool isIdentifier, int qtyArgs, integer idxInOriginal, integer idxInNormalized)
Definition program.cpp:178
void AssembleBinaryOp(String &op, integer idxInOriginal, integer idxInNormalized)
Definition program.cpp:525
void AssembleCondFinalize_Q(integer idxInOriginal, integer idxInNormalized)
Definition program.cpp:715
Program(Compiler &pCompiler, ExpressionVal &pExpression, MonoAllocator *ctAlloc)
Definition program.cpp:21
void AssembleConstant(Box &value, integer idxInOriginal, integer idxInNormalized)
Definition program.cpp:164
Compiler & compiler
The compiler that created this object.
Definition program.hpp:29
StdVectorMA< Expression > ctNestedExpressions
Definition program.hpp:50
void AssembleCondFinalize_F(integer idxInOriginal, integer idxInNormalized)
Definition program.cpp:765
integer commandsCount
The number of commands.
Definition program.hpp:46
VM::Command * commands
The array of commands.
Definition program.hpp:43
void AssembleCondFinalize_T(integer idxInOriginal, integer idxInNormalized)
Definition program.cpp:744
DbgInformation DbgInfo
Operation code of this command. Available only with debug-builds.
void DbgDisableBufferReplacementWarning()
Definition tastring.hpp:236
@ ReplaceVerbalOperatorsToDefinedLetterCase
See sibling flag #"Normalization::ReplaceVerbalOperatorsToSymbolic".
@ UnknownIdentifier
Compile-time exception thrown when an expression uses an unknown identifier name.
@ UnknownFunction
Compile-time exception thrown when an expression uses an unknown function name.
@ NamedExpressionNotFound
Compile-time exception thrown when an expression refers to an unknown named nested expression.
void Destruct(T &object)
Definition tmp.hpp:82
Definition alox.cpp:14
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
lang::integer integer
Type alias in namespace #"%alib".
Definition integers.hpp:149
boxing::Box Box
Type alias in namespace #"%alib".
Definition box.hpp:1128
strings::TString< character > String
Type alias in namespace #"%alib".
Definition string.hpp:2165
exceptions::Exception Exception
Type alias in namespace #"%alib".
LocalString< 128 > String128
Type alias name for #"TLocalString;TLocalString<character,128>".
boxing::FIsTrue FIsTrue
Type alias in namespace #"%alib".
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace #"%alib".
std::vector< T, StdMA< T > > StdVectorMA
Type alias in namespace #"%alib".
TIntegral Integral() const
Definition enum.hpp:87
bool IsEnumType() const
Definition enum.hpp:141
bool NonConstArgIsResult
Output: Used with optimization, see this struct's documentation for more information.
CallbackDecl Callback
Output: The native C++ callback function to be set by one of the plug-ins.
StdVectorMA< Box > * Stack
Definition scope.hpp:101
CompilerPlugin * Plugin
The plug-in that provided the callback or constant.