21namespace alib {
namespace expressions {
namespace detail {
27, Parameter ( program )
28, ResultType ( resultType )
30 + static_cast<
uinteger>(idxOriginal ) )
31, DecompileSymbol ( functionOrOp )
35#define POS_IN_EXPR_STR (cmd.ExpressionPositions & ( (1UL << (bitsof(integer) / 2 - 1) ) -1 ) )
37# define NORMPOS_IN_EXPR_STR (cmd.ExpressionPositions >> (bitsof(integer)/2 ) )
53 run( program, scope );
60 scope.
Stack->pop_back();
70 auto& stack= *scope.
Stack;
74 for(
auto* nestedExpression : nestedExpressions )
78 for(
auto it2= nestedExpressions.begin() ; it2!= nestedExpressions.end(); ++it2 )
81 it2 + 1 != nestedExpressions.end()
83 : nestedExpression->Name() );
87 nestedExpressions.emplace_back( &program.
expression );
90 for(
integer programCounter= 0; programCounter < program.
Length() ; ++ programCounter )
92 const Command& cmd= program.
At(programCounter);
114 "Result type mismatch during command execution:\n"
115 " In expression: {!Q} {{{}}}\n"
117 " Identifier: {} ({})\n"
118 " Expected type: {!Q<>} (aka {})\n"
119 " Result type: {!Q<>} (aka {})\n"
120 " Result value: {}\n",
136 *(stack.end() - cmd.
QtyArgs() )=
153 case DCT::FunctionCall:
166 case DCT::OptimizationConstant:
167 ALIB_ERROR(
"EXPRVM",
"Must not be set with function calls")
169 default:
ALIB_ERROR(
"Illegal switch state.")
break;
176 fmt.
Format( msg,
"Result type mismatch during command execution:\n"
177 " In expression: {!Q} {{{}}}\n"
181 " Expected type: {!Q<>} (aka {})\n"
182 " Result type: {!Q<>} (aka {})\n"
183 " Result value: {}\n"
184 " Parameter values: ",
193 fmt.
Format( msg,
"({!Q'} {!Q<>}",
197 fmt.
Format( msg,
", {!Q'} {!Q<>}",
220 catch( std::exception& stdException )
229 stdException.what() );
239 if( !stack.back().Call<
FIsTrue>() )
256 String nestedExpressionName= (stack.end()-2)->Unbox<
String>();
270 stack.erase( stack.end() - 2 );
275 nestedExpressionName );
285 nestedExpressionName );
288 nestedExpressionName );
292 run( *
dynamic_cast<Program*
>(nested.
Get()->GetProgram()), scope);
294 if( !(stack.end()-2)->IsSameType(stack.back()) )
297 nestedExpressionName,
305 stack.erase( stack.end()-3, stack.end() -1 );
314 default:
ALIB_ERROR(
"Illegal switch state.")
break;
321 nestedExpressions.pop_back();
326 "Internal error: Stack increased by {} (instead of 1) after run of expression program.",
327 stack.size() - initialStackSize )
331 "Wrong result type of program execution:\n"
332 " Expected Type: {!Q<>} (aka {})\n"
333 " Result Type: {!Q<>} (aka {})\n"
334 " Result value: {}\n"
335 " In expression: {!Q}"
351 #define PushNode(node) nodeStack.emplace_back( node )
352 #define PopNode nodeStack.pop_back()
353 #define Lhs (*(nodeStack.end() - 2) )
354 #define Rhs nodeStack.back()
355 #define Arg nodeStack.back()
357 std::vector<AST*> nodeStack;
359 std::stack <PC> conditionalStack;
366 integer positionInExpression= POS_IN_EXPR_STR;
379 for(
integer i= 0 ; i< 2 ; ++i )
389 positionInExpression ) );
397 positionInExpression );
400 positionInExpression );
461 default:
ALIB_ERROR(
"Illegal switch state.")
break;
466 while( !conditionalStack.empty() && conditionalStack.top() == pc )
468 AST* F= Arg; PopNode;
469 AST* T= Arg; PopNode;
471 conditionalStack.pop();
484 "VM AST generation error: NodeImpl stack must contain one element. Elements: {}", nodeStack.size())
486 "VM Program List error: Conditional stack after listing not 0 but {}", conditionalStack.size())
488 return nodeStack.back();
500void writeArgPositions(
AString& target, std::vector<VirtualMachine::PC>& resultStack,
integer qtyArgs )
502 for(
integer argNo= qtyArgs ; argNo > 0 ; --argNo )
504 target << (argNo == qtyArgs ?
"" :
", ")
505 << (qtyArgs-argNo) <<
"{"
506 << (
static_cast<integer>(resultStack.size()) == argNo ? 0
507 : *(resultStack.end() - argNo - 1) + 1 )
508 <<
".." << *(resultStack.end() - argNo )
549 for(
int i= 0 ; i < 7 ; ++i )
564 #define FMT(qtyArgs) \
565 { if( cmd.DbgInfo.Plugin ) \
566 description << ", CP=\"" << cmd.DbgInfo.Plugin->Name<< '\"'; \
568 writeArgPositions(argpos,resultStack,qtyArgs); \
571 program.compiler.TypeName( cmd.ResultType ), \
577 NORMPOS_IN_EXPR_STR, "_^_" ); }
580 #define PushResult resultStack.emplace_back( pc )
581 #define PopResult resultStack.pop_back()
582 #define ResultPos resultStack.back()
584 std::vector<PC> resultStack; // The last command of the current results on the stack
585 std::stack <PC> conditionalStack; // Stores the target of jump commands behind the T of
586 // conditional term "Q : T : F". In other words, the
590 for( integer pc= 0 ; pc < program.Length() ; ++pc )
592 const Command& cmd= program.At(pc);
595 String128 description;
596 ALIB_WARNINGS_ALLOW_BITWISE_SWITCH
597 ALIB_WARNINGS_ALLOW_SPARSE_ENUM_SWITCH
598 switch( cmd.OpCode() )
600 case Command::OpCodes::Subroutine:
602 if( cmd.Parameter.NestedProgram == nullptr
603 || cmd.Parameter.NestedProgram == &program )
606 operation << ( cmd.Parameter.NestedProgram == nullptr ? "Expr(name, type)"
607 : "Expr(name, type, throw)" );
608 description << "Nested expr. searched at evaluation-time";
614 operation << cmd.DecompileSymbol
615 << "\"" << cmd.Parameter.NestedProgram->expression.Name() << '\"';
616 description << "Nested expr. searched at compile-time";
623 case Command::OpCodes::Constant:
626 char uetzelchen= cmd.ResultType.IsType<String>() ? '\"' : '\'';
627 operation << uetzelchen << cmd.ResultType << uetzelchen;
628 description << (cmd.TerminalType() == DCT::LiteralConstant ? "Literal constant"
629 : "Optimization constant" );
635 case Command::OpCodes::Function:
637 operation << cmd.DbgInfo.Callback
638 << "(#" << (cmd.QtyArgs() < 0 ? 0 : cmd.QtyArgs()) << ')';
640 NString descr= nullptr;
642 switch( cmd.TerminalType() )
645 descr = "Unary operator";
649 descr = "Binary operator";
652 case DCT::Identifier:
653 descr = "Identifier";
656 case DCT::FunctionCall:
657 if( cmd.QtyArgs() < 0 )
659 descr =
"Identifier";
663 description <<
"Function \"";
664 if( cmd.QtyArgs() == 0 )
665 description << cmd.DecompileSymbol <<
"()\"";
667 description << cmd.DecompileSymbol <<
"(#"
668 << cmd.QtyArgs() <<
")\"";
675 case DCT::OptimizationConstant:
676 ALIB_ERROR(
"EXPRVM",
"Must not be set with function calls")
678 default:
ALIB_ERROR(
"Illegal switch state.")
break;
680 if( descr.IsNotNull() )
681 description << descr <<
' ' << decSym << cmd.DecompileSymbol << decSym;
683 stackSize+= 1 - (cmd.QtyArgs() > 0 ? cmd.QtyArgs() : 0 );
684 FMT(cmd.QtyArgs() < 0 ? 0 : cmd.QtyArgs() )
685 for(
integer i= 0 ; i< cmd.QtyArgs() ; ++i )
693 operation << ( pc + cmd.Parameter.Distance ) <<
" (absolute)" ;
694 description <<
"'?'";
702 conditionalStack.emplace( pc + cmd.Parameter.Distance -1 );
703 operation << ( pc + cmd.Parameter.Distance ) <<
" (absolute)" ;
704 description <<
"':'";
710 default:
ALIB_ERROR(
"Illegal switch state.") break;
716 while( !conditionalStack.empty() && conditionalStack.top() == pc )
721 conditionalStack.pop();
733 "VM Program List error: Stack size after listing not 1 but {}. Listing follows.\n",
734 stackSize, text.Buffer )
737 "VM Program
List error: Resultstack after listing not 1 but {}. Listing follows.\n
",
738 resultStack.size(), text.Buffer )
740 ALIB_ASSERT_ERROR( lastLineWidth!= 0 || conditionalStack.size() == 0, "EXPRVM
",
741 "VM Program
List error: Conditional stack after listing not 0 but {}.Listing follows.\n
",
742 conditionalStack, text.Buffer )
745 return std::move(text.Buffer);
750#undef POS_IN_EXPR_STR
761}}} // namespace [alib::expressions::detail]
762#include "alib/lang/callerinfo_methods.hpp
"
bool IsSameType(const Box &other) const
const std::type_info & TypeID() const
ALIB_API NString TypeName(Type box)
String CfgNestedExpressionOperator
Compilation CfgCompilation
Compilation flags.
String CfgNestedExpressionThrowIdentifier
virtual ALIB_API Expression GetNamed(const String &name)
String GetOriginalString() const
String GetNormalizedString() const
Compiler & compiler
The compiler that created this object.
ALIB_API const Box & ResultType() const
ExpressionVal & expression
The expression that this program evaluates.
VM::Command & At(VM::PC pc)
constexpr ListingTypes TerminalType() const
OpCodes
The opcode type of VM commands.
@ Subroutine
Invokes another program.
@ Constant
Pushes a constant to the stack.
@ Function
Invokes a C++ callback function.
@ JumpIfFalse
Jumps if top of the stack indicates false.
DbgInformation DbgInfo
Operation code of this command. Available only with debug-builds.
Command(const Box &value, bool isOptimization, integer idxOriginal, integer idxNormalized)
OperationParam Parameter
The parameter of the operation.
constexpr OpCodes OpCode() const
ListingTypes
Denotes the type of parsing de-compilation information attached to the command.
const String & GetResource(const NString &name)
ALIB_API const Enum & Type() const
Exception & Add(const lang::CallerInfo &ci, TEnum type, TArgs &&... args)
TAString & ShortenTo(integer newLength)
constexpr integer Length() const
#define ALIB_CALLER_NULLED
#define ALIB_WARNINGS_ALLOW_BITWISE_SWITCH
#define ALIB_WARNINGS_RESTORE
#define ALIB_WARNINGS_ALLOW_SPARSE_ENUM_SWITCH
#define ALIB_LOCK_RECURSIVE_WITH(lock)
#define ALIB_ASSERT_ERROR(cond,...)
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
#define ALIB_DCS_WITH(CS)
@ CallbackExceptionFallThrough
@ 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::ExpressionsCamp EXPRESSIONS
The singleton instance of ALib Camp class ExpressionsCamp.
containers::List< TAllocator, T, TRecycling > List
Type alias in namespace alib.
strings::TString< character > String
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
StdVectorMono< ExpressionVal * > NestedExpressions
Stack of nested expressions called during evaluation. Used to detect cyclic expressions.
lang::DbgCriticalSections dcs
StdVectorMono< Box > * Stack
VMMembers * vmMembers
The members used for the virtual machine. Available only with evaluation-time instances.
virtual ALIB_API void reset()
Abstract syntax tree node representing binary operators.
Abstract syntax tree node representing ternary operator Q ? T : F.
Abstract syntax tree node representing a function call.
List< MonoAllocator, AST * > Arguments
The argument nodes.
Abstract syntax tree node representing identifiers.
Abstract syntax tree node representing identifiers.
Box Value
The value of the literal.
Abstract syntax tree node representing unary operators.
integer Position
Position in original expression string.
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)
Program * NestedProgram
The nested virtual machine program to invoke.
PC Distance
A distance to jump.
CallbackDecl Callback
A C++ callback function to invoke.