10#if !defined (HPP_ALIB_EXPRESSIONS_DETAIL_VIRTUAL_MACHINE)
14#if !defined (HPP_ALIB_LANG_FORMAT_PARAGRAPHS)
18#if !defined (HPP_ALIB_EXPRESSIONS_COMPILERPLUGIN)
22#if !defined (HPP_ALIB_EXPRESSIONS_DETAIL_PROGRAM)
26#if !defined (HPP_ALIB_EXPRESSIONS_DETAIL_AST)
29# if !defined (HPP_ALIB_LANG_CAMP_INLINES)
34namespace alib {
namespace expressions {
namespace detail {
40, Operation ( program )
41, ResultType ( resultType )
43 + static_cast<
uinteger>(idxOriginal ) )
45, DecompileSymbol ( functionOrOp )
49#define POS_IN_EXPR_STR (cmd.ExpressionPositions & ( (1UL << (bitsof(integer) / 2 - 1) ) -1 ) )
51# define NORMPOS_IN_EXPR_STR (cmd.ExpressionPositions >> (bitsof(integer)/2 ) )
67 run( program, scope );
74 scope.
Stack.pop_back();
85 auto& stack= scope.
Stack;
97 : nestedExpression->Name() );
104 for(
integer programCounter= 0; programCounter < program.
Length() ; ++ programCounter )
106 const Command& cmd= program.
At(programCounter);
108 switch( cmd.
Which() )
127 "Result type mismatch during command execution:\n"
128 " In expression: {!Q} {{{}}}\n"
130 " Identifier: {} ({})\n"
131 " Expected type: {!Q<>} (aka {})\n"
132 " Result type: {!Q<>} (aka {})\n"
133 " Result value: {}\n",
179 case DCT::OptimizationConstant:
180 ALIB_ERROR(
"EXPRVM",
"Must not be set with function calls")
185 fmt->Format( msg,
"Result type mismatch during command execution:\n"
186 " In expression: {!Q} {{{}}}\n"
190 " Expected type: {!Q<>} (aka {})\n"
191 " Result type: {!Q<>} (aka {})\n"
192 " Result value: {}\n"
193 " Parameter values: ",
202 fmt->Format( msg,
"({!Q'} {!Q<>}",
206 fmt->Format( msg,
", {!Q'} {!Q<>}",
230 catch( std::exception& stdException )
239 stdException.what() );
249 if( !stack.back().Call<
FIsTrue>() )
266 String nestedExpressionName= (stack.end()-2)->Unbox<String>();
280 stack.erase( stack.end() - 2 );
285 nestedExpressionName );
295 nestedExpressionName );
298 nestedExpressionName );
302 run( *
dynamic_cast<Program*
>(nested.get()->GetProgram()), scope);
304 if( !(stack.end()-2)->IsSameType(stack.back()) )
307 nestedExpressionName,
315 stack.erase( stack.end()-3, stack.end() -1 );
333 "Internal error: Stack increased by {} (instead of 1) after run of expression program.",
334 stack.size() - initialStackSize )
338 "Wrong result type of program execution:\n"
339 " Expected Type: {!Q<>} (aka {})\n"
340 " Result Type: {!Q<>} (aka {})\n"
341 " Result value: {}\n"
342 " In expression: {!Q}"
358 #define PushNode(node) nodeStack.emplace_back( node )
359 #define PopNode nodeStack.pop_back()
360 #define Lhs (*(nodeStack.end() - 2) )
361 #define Rhs nodeStack.back()
362 #define Arg nodeStack.back()
364 std::vector<AST*> nodeStack;
366 std::stack <PC> conditionalStack;
373 integer positionInExpression= POS_IN_EXPR_STR;
376 switch( cmd.
Which() )
385 for(
integer i= 0 ; i< 2 ; ++i )
395 positionInExpression ) );
403 positionInExpression );
406 positionInExpression );
470 while( !conditionalStack.empty() && conditionalStack.top() == pc )
472 AST* F= Arg; PopNode;
473 AST* T= Arg; PopNode;
475 conditionalStack.pop();
488 "VM AST generation error: NodeImpl stack must contain one element. Elements: {}", nodeStack.size())
490 "VM Program List error: Conditional stack after listing not 0 but {}", conditionalStack.size())
492 return nodeStack.back();
504void writeArgPositions(
AString& target, std::vector<VirtualMachine::PC>& resultStack,
integer qtyArgs )
506 for(
integer argNo= qtyArgs ; argNo > 0 ; --argNo )
508 target << (argNo == qtyArgs ?
"" :
", ")
509 << (qtyArgs-argNo) <<
"{"
510 << (
static_cast<integer>(resultStack.size()) == argNo ? 0
511 : *(resultStack.end() - argNo - 1) + 1 )
512 <<
".." << *(resultStack.end() - argNo )
553 for(
int i= 0 ; i < 7 ; ++i )
568 #define FMT(qtyArgs) \
569 { if( cmd.DbgInfo.Plugin ) description << ", CP=\"" << cmd.DbgInfo.Plugin->Name<< '\"'; \
570 String256 argpos; writeArgPositions(argpos,resultStack,qtyArgs); \
573 program.compiler.TypeName( cmd.ResultType ), \
579 NORMPOS_IN_EXPR_STR, "_^_" ); }
582 #define PushResult resultStack.emplace_back( pc )
583 #define PopResult resultStack.pop_back()
584 #define ResultPos resultStack.back()
586 std::vector<PC> resultStack; // The last command of the current results on the stack
587 std::stack <PC> conditionalStack; // Stores the target of jump commands behind the T of
588 // conditional term "Q : T : F". In other words, the
592 for( integer pc= 0 ; pc < program.Length() ; ++pc )
594 const Command& cmd= program.At(pc);
597 String128 description;
598 ALIB_WARNINGS_ALLOW_BITWISE_SWITCH
599 switch( cmd.Which() )
601 case Command::OpCodes::Subroutine:
603 if( cmd.Operation.NestedProgram == nullptr
604 || cmd.Operation.NestedProgram == &program )
607 operation << ( cmd.Operation.NestedProgram == nullptr ? "Expr(name, type)"
608 : "Expr(name, type, throw)" );
609 description << "Nested expr. searched at evaluation-time";
615 operation << cmd.DecompileSymbol
616 << "\"" << cmd.Operation.NestedProgram->expression.Name() << '\"';
617 description << "Nested expr. searched at compile-time";
624 case Command::OpCodes::Constant:
627 char uetzelchen= cmd.Operation.Value.IsType<String>() ? '\"' : '\'';
628 operation << uetzelchen << cmd.Operation.Value << uetzelchen;
629 description << (cmd.DecompileType == DCT::LiteralConstant ? "Literal constant"
630 : "Optimization constant" );
636 case Command::OpCodes::Function:
638 operation << cmd.DbgInfo.Callback
639 << "(#" << (cmd.QtyFunctionArgs < 0 ? 0 : cmd.QtyFunctionArgs) << ')';
641 NString descr= nullptr;
643 switch( cmd.DecompileType )
646 descr = "Unary operator";
650 descr = "Binary operator";
654 if( cmd.QtyFunctionArgs < 0 )
656 descr = "Identifier";
660 description <<
"Function \"";
661 if( cmd.QtyFunctionArgs == 0 )
662 description << cmd.DecompileSymbol <<
"()\"";
664 description << cmd.DecompileSymbol <<
"(#"
665 << cmd.QtyFunctionArgs <<
")\"";
672 case DCT::OptimizationConstant:
673 ALIB_ERROR(
"EXPRVM",
"Must not be set with function calls")
675 if( descr.IsNotNull() )
676 description << descr <<
' ' << decSym << cmd.DecompileSymbol << decSym;
678 stackSize+= 1 - (cmd.QtyFunctionArgs > 0 ? cmd.QtyFunctionArgs : 0 );
679 FMT(cmd.QtyFunctionArgs < 0 ? 0 : cmd.QtyFunctionArgs)
680 for(
integer i= 0 ; i< cmd.QtyFunctionArgs ; ++i )
686 case Command::OpCodes::JumpIfFalse:
688 operation << ( pc + cmd.Operation.Distance ) <<
" (absolute)" ;
689 description <<
"'?'";
695 case Command::OpCodes::Jump:
697 conditionalStack.emplace( pc + cmd.Operation.Distance -1 );
698 operation << ( pc + cmd.Operation.Distance ) <<
" (absolute)" ;
699 description <<
"':'";
709 while( !conditionalStack.empty() && conditionalStack.top() == pc )
714 conditionalStack.pop();
726 "VM Program List error: Stack size after listing not 1 but {}. Listing follows.\n",
727 stackSize, text.Buffer )
730 "VM Program
List error: Resultstack after listing not 1 but {}. Listing follows.\n
",
731 resultStack.size(), text.Buffer )
733 ALIB_ASSERT_ERROR( lastLineWidth!= 0 || conditionalStack.size() == 0, "EXPRVM
",
734 "VM Program
List error: Conditional stack after listing not 0 but {}.Listing follows.\n
",
735 conditionalStack, text.Buffer )
738 text.Formatter->Release();
740 return std::move(text.Buffer);
745#undef POS_IN_EXPR_STR
756}}} // namespace [alib::expressions::detail]
bool IsSameType(const Box &other) const
const std::type_info & TypeID() const
virtual ALIB_API SPExpression GetNamed(const String &name)
ALIB_API NString TypeName(Type box)
String CfgNestedExpressionOperator
Compilation CfgCompilation
String CfgNestedExpressionThrowIdentifier
String GetOriginalString() const
String GetNormalizedString() const
ALIB_API const Box & ResultType() const
VM::Command & At(VM::PC pc)
@ Subroutine
Invokes another program.
@ Function
Invokes a C++ callback function.
@ Constant
Pushes a constant to the stack.
@ JumpIfFalse
Jumps if top of the stack indicates false.
DecompileInfoType DecompileType
Command(const Box &value, bool isOptimization, integer idxOriginal, integer idxNormalized)
static ALIB_API void run(Program &program, Scope &scope)
static ALIB_API alib::Box Run(Program &program, Scope &scope)
static ALIB_API AString DbgList(Program &program)
static ALIB_API AST * Decompile(Program &program, MonoAllocator &allocator)
const String & GetResource(const NString &name)
ALIB_API const Enum & Type() const
Exception & Add(const NCString &file, int line, const NCString &func, TEnum type, TArgs &&... args)
ALIB_FORCE_INLINE T * Emplace(TArgs &&... args)
strings::TString< TChar > EmplaceString(const strings::TString< TChar > &src)
TAString & ShortenTo(integer newLength)
constexpr integer Length() const
#define ALIB_CALLER_NULLED
#define ALIB_WARNINGS_ALLOW_BITWISE_SWITCH
#define ALIB_WARNINGS_RESTORE
#define ALIB_ASSERT_ERROR(cond,...)
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
#define ALIB_CALLER_PRUNED
@ CallbackExceptionFallThrough
std::shared_ptr< Expression > SPExpression
@ NestedExpressionResultTypeError
@ CircularNestedExpressions
@ NamedExpressionNotFound
Compile-time exception thrown when an expression refers to an unknown named nested expression.
@ NestedExpressionNotFoundET
@ WhenEvaluatingNestedExpression
@ CircularNestedExpressionsInfo
lang::uinteger uinteger
Type alias in namespace alib.
expressions::Expressions EXPRESSIONS
monomem::List< T, TRecycling > List
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
virtual ALIB_API void Reset()
std::vector< alib::Box > Stack
std::vector< Expression *, StdContMA< Expression * > > NestedExpressions
List< AST * > Arguments
The argument nodes.
Box Value
The value of the literal.
Box Value
A constant value to push to the stack.
Program * NestedProgram
The nested virtual machine program to invoke.
PC Distance
A distance to jump.
CallbackDecl Callback
A C++ callback function to invoke.