8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Symbol ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
22 module ALib.Expressions.Impl;
23 import ALib.Characters.Functions;
41 const String& functionOrOp,
50#define POS_IN_EXPR_STR (cmd.ExpressionPositions & ( (1UL << (bitsof(integer) / 2 - 1) ) -1 ) )
52# define NORMPOS_IN_EXPR_STR (cmd.ExpressionPositions >> (bitsof(integer)/2 ) )
67 run( program, scope );
74 scope.
Stack->pop_back();
83 auto& stack= *scope.
Stack;
87 for(
auto* nestedExpression : nestedExpressions )
88 if( nestedExpression == &program.
expression ) {
90 for(
auto it2= nestedExpressions.begin() ; it2!= nestedExpressions.end(); ++it2 )
93 it2 + 1 != nestedExpressions.end()
95 : nestedExpression->Name() );
99 nestedExpressions.emplace_back( &program.
expression );
102 for(
integer programCounter= 0; programCounter < program.
Length() ; ++ programCounter ) {
103 const Command& cmd= program.
At(programCounter);
123 "Result type mismatch during command execution:\n"
124 " In expression: \"{}\" {{{}}}\n"
126 " Identifier: {} ({})\n"
127 " Expected type: <{}> (aka {})\n"
128 " Result type: <{}> (aka {})\n"
129 " Result value: {}\n",
144 *(stack.end() - cmd.
QtyArgs() )=
159 case DCT::FunctionCall:
172 case DCT::OptimizationConstant:
173 ALIB_ERROR(
"EXPRVM",
"Must not be set with function calls")
175 default:
ALIB_ERROR(
"EXPR",
"Illegal switch state." )
break;
182 fmt.
Format( msg,
"Result type mismatch during command execution:\n"
183 " In expression: {!Q} {{{}}}\n"
187 " Expected type: {!Q<>} (aka {})\n"
188 " Result type: {!Q<>} (aka {})\n"
189 " Result value: {}\n"
190 " Parameter values: ",
199 fmt.
Format( msg,
"({!Q'} {!Q<>}",
203 fmt.
Format( msg,
", {!Q'} {!Q<>}",
224 catch( std::exception& stdException )
232 stdException.what() );
241 if( !stack.back().Call<
FIsTrue>() )
258 String nestedExpressionName= (stack.end()-2)->Unbox<
String>();
270 stack.erase( stack.end() - 2 );
275 nestedExpressionName );
285 nestedExpressionName );
288 nestedExpressionName );
292 run( *
static_cast<Program*
>(nested.
Get()->GetProgram()), scope);
294 if( !(stack.end()-2)->IsSameType(stack.back()) ) {
296 nestedExpressionName,
304 stack.erase( stack.end()-3, stack.end() -1 );
313 default:
ALIB_ERROR(
"EXPR",
"Illegal switch state." )
break;
320 nestedExpressions.pop_back();
325 "Internal error: Stack increased by {} (instead of 1) after run of expression program.",
326 stack.size() - initialStackSize )
330 "Wrong result type of program execution:\n"
331 " Expected Type: <{}> (aka {})\n"
332 " Result Type: <{}> (aka {})\n"
333 " Result value: {}\n"
334 " In expression: \"{}\""
349 #define PushNode(node) nodeStack.emplace_back( node )
350 #define PopNode nodeStack.pop_back()
351 #define Lhs (*(nodeStack.end() - 2) )
352 #define Rhs nodeStack.back()
353 #define Arg nodeStack.back()
355 std::vector<AST*> nodeStack;
357 std::stack <PC> conditionalStack;
363 integer positionInExpression= POS_IN_EXPR_STR;
375 for(
integer i= 0 ; i< 2 ; ++i ) {
384 positionInExpression ) );
392 positionInExpression );
395 positionInExpression );
452 default:
ALIB_ERROR(
"EXPR",
"Illegal switch state.")
break;
457 while( !conditionalStack.empty() && conditionalStack.top() == pc ) {
458 AST* F= Arg; PopNode;
459 AST* T= Arg; PopNode;
461 conditionalStack.pop();
474 "VM AST generation error: NodeImpl stack must contain one element. Elements: {}",
477 "VM Program List error: Conditional stack after listing not 0 but {}",
478 conditionalStack.size())
480 return nodeStack.back();
492void writeArgPositions(
AString& target, std::vector<VirtualMachine::PC>& resultStack,
494 for(
integer argNo= qtyArgs ; argNo > 0 ; --argNo ) {
495 target << (argNo == qtyArgs ?
"" :
", ")
496 << (qtyArgs-argNo) <<
"{"
497 << (
integer(resultStack.size()) == argNo ? 0
498 : *(resultStack.end() - argNo - 1) + 1 )
499 <<
".." << *(resultStack.end() - argNo )
535 for(
int i= 0 ; i < 7 ; ++i ) {
536 hdlArgs[i+1]=
EXPRESSIONS.GetResource(hdlKeyNumbered << i );
547 #define FMT(qtyArgs) \
548 { if( cmd.DbgInfo.Plugin ) \
549 description << ", CP=\"" << cmd.DbgInfo.Plugin->Name<< '\"'; \
551 writeArgPositions(argpos,resultStack,qtyArgs); \
554 program.compiler.TypeName( cmd.ResultType ), \
560 NORMPOS_IN_EXPR_STR, "_^_" ); }
563 #define PushResult resultStack.emplace_back( pc )
564 #define PopResult resultStack.pop_back()
565 #define ResultPos resultStack.back()
567 std::vector<PC> resultStack; // The last command of the current results on the stack
568 std::stack <PC> conditionalStack; // Stores the target of jump commands behind the T of
569 // conditional term "Q : T : F". In other words, the
573 for( integer pc= 0 ; pc < program.Length() ; ++pc ) {
574 const Command& cmd= program.At(pc);
577 String128 description;
578 ALIB_WARNINGS_ALLOW_BITWISE_SWITCH
579 ALIB_WARNINGS_ALLOW_SPARSE_ENUM_SWITCH
580 switch( cmd.OpCode() ) {
581 case Command::OpCodes::Subroutine:
583 if( cmd.Parameter.NestedProgram == nullptr
584 || cmd.Parameter.NestedProgram == &program )
587 operation << ( cmd.Parameter.NestedProgram == nullptr ? "Expr(name, type)"
588 : "Expr(name, type, throw)" );
589 description << "Nested expr. searched at evaluation-time";
593 operation << cmd.DecompileSymbol
594 << "\"" << cmd.Parameter.NestedProgram->expression.Name() << '\"';
595 description << "Nested expr. searched at compile-time";
602 case Command::OpCodes::Constant:
605 char uetzelchen= cmd.ResultType.IsType<String>() ? '\"' : '\'';
606 operation << uetzelchen << cmd.ResultType << uetzelchen;
607 description << (cmd.TerminalType() == DCT::LiteralConstant ? "Literal constant"
608 : "Optimization constant" );
614 case Command::OpCodes::Function:
616 operation << cmd.DbgInfo.Callback
617 << "(#" << (cmd.QtyArgs() < 0 ? 0 : cmd.QtyArgs()) << ')';
619 NString descr= nullptr;
621 switch( cmd.TerminalType() ) {
623 descr = "Unary operator";
627 descr = "Binary operator";
630 case DCT::Identifier:
631 descr = "Identifier";
634 case DCT::FunctionCall:
635 if( cmd.QtyArgs() < 0 ) {
636 descr =
"Identifier";
640 description <<
"Function \"";
641 if( cmd.QtyArgs() == 0 )
642 description << cmd.DecompileSymbol <<
"()\"";
644 description << cmd.DecompileSymbol <<
"(#"
645 << cmd.QtyArgs() <<
")\"";
652 case DCT::OptimizationConstant:
653 ALIB_ERROR(
"EXPRVM",
"Must not be set with function calls")
655 default:
ALIB_ERROR(
"EXPR",
"Illegal switch state.")
break;
657 if( descr.IsNotNull() )
658 description << descr <<
' ' << decSym << cmd.DecompileSymbol << decSym;
660 stackSize+= 1 - (cmd.QtyArgs() > 0 ? cmd.QtyArgs() : 0 );
661 FMT(cmd.QtyArgs() < 0 ? 0 : cmd.QtyArgs() )
662 for(
integer i= 0 ; i< cmd.QtyArgs() ; ++i )
670 operation << ( pc + cmd.Parameter.Distance ) <<
" (absolute)" ;
671 description <<
"'?'";
679 conditionalStack.emplace( pc + cmd.Parameter.Distance -1 );
680 operation << ( pc + cmd.Parameter.Distance ) <<
" (absolute)" ;
681 description <<
"':'";
687 default:
ALIB_ERROR(
"EXPR",
"Illegal switch state.") break;
693 while( !conditionalStack.empty() && conditionalStack.top() == pc ) {
697 conditionalStack.pop();
709 "VM Program List error: Stack size after listing not 1 but {}. Listing follows.\n",
710 stackSize, text.Buffer )
713 "VM Program List error: Resultstack after listing not 1 but {}. Listing follows.\n",
714 resultStack.size(), text.Buffer )
717 "VM Program List error: Conditional stack after listing not 0 but {}. Listing follows.\n",
718 conditionalStack.size(), text.Buffer )
721 return std::move(text.Buffer);
726#undef POS_IN_EXPR_STR
bool IsSameType(const Box &other) const
const std::type_info & TypeID() const
Exception & Add(const lang::CallerInfo &ci, TEnum type, TArgs &&... args)
ALIB_DLL const Enum & Type() const
Compilation CfgCompilation
Compilation flags.
ALIB_DLL NString TypeName(Type box)
virtual ALIB_DLL Expression GetNamed(const String &name)
String CfgNestedExpressionThrowIdentifier
String CfgNestedExpressionOperator
String GetNormalizedString() const
String GetOriginalString() const
ExpressionVal & expression
The expression that this program evaluates.
ALIB_DLL const Box & ResultType() const
VM::Command & At(VM::PC pc)
Compiler & compiler
The compiler that created this object.
ListingTypes
Denotes the type of parsing de-compilation information attached to the command.
@ NestedExpression
Command results from a nested expression.
DbgInformation DbgInfo
Operation code of this command. Available only with debug-builds.
OperationParam Parameter
The parameter of the operation.
OpCodes
The opcode type of VM commands.
@ Subroutine
Invokes another program.
@ Function
Invokes a C++ callback function.
@ JumpIfFalse
Jumps if top of the stack indicates false.
@ Constant
Pushes a constant to the stack.
uinteger ExpressionPositions
Command(const Box &value, bool isOptimization, integer idxOriginal, integer idxNormalized)
constexpr OpCodes OpCode() const
int16_t bits
Operation code of this command.
constexpr ListingTypes TerminalType() const
TAString & ShortenTo(integer newLength)
constexpr integer Length() const
#define ALIB_BOXING_VTABLE_DEFINE(TMapped, Identifier)
#define ALIB_CALLER_NULLED
#define ALIB_WARNINGS_ALLOW_BITWISE_SWITCH
#define ALIB_WARNINGS_RESTORE
#define ALIB_ERROR(domain,...)
#define ALIB_WARNINGS_ALLOW_SPARSE_ENUM_SWITCH
#define ALIB_LOCK_RECURSIVE_WITH(lock)
#define ALIB_DCS_WITH(CS)
#define ALIB_ASSERT_ERROR(cond, domain,...)
@ CallbackExceptionFallThrough
@ NestedExpressionResultTypeError
@ CircularNestedExpressions
@ NamedExpressionNotFound
Compile-time exception thrown when an expression refers to an unknown named nested expression.
@ NestedExpressionNotFoundET
@ WhenEvaluatingNestedExpression
@ CircularNestedExpressionsInfo
LocalString< 512 > String512
Type alias name for TLocalString<character,512>.
NLocalString< 64 > NString64
Type alias name for TLocalString<nchar,64>.
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
LocalString< 128 > String128
Type alias name for TLocalString<character,128>.
lang::integer integer
Type alias in namespace alib.
strings::TString< nchar > NString
Type alias in namespace alib.
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
format::Paragraphs Paragraphs
Type alias in namespace alib.
format::Formatter Formatter
Type alias in namespace alib.
boxing::Box Box
Type alias in namespace alib.
exceptions::Exception Exception
Type alias in namespace alib.
strings::TString< character > String
Type alias in namespace alib.
expressions::ExpressionsCamp EXPRESSIONS
The singleton instance of ALib Camp class ExpressionsCamp.
boxing::FIsTrue FIsTrue
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
StdVectorMA< ExpressionVal * > NestedExpressions
Stack of nested expressions called during evaluation. Used to detect cyclic expressions.
VMMembers * EvalScopeVMMembers
The members used for the virtual machine. Available only with evaluation-time instances.
StdVectorMA< Box > * Stack
lang::DbgCriticalSections DCS
virtual ALIB_DLL 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.
ListMA< 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 the original expression string.
static Scope * getExpressionCTScope(ExpressionVal &ev)
static ALIB_DLL AST * Decompile(Program &program, MonoAllocator &allocator)
static ALIB_DLL alib::Box Run(Program &program, Scope &scope)
static ALIB_DLL void run(Program &program, Scope &scope)
static ALIB_DLL AString DbgList(Program &program)
PC Distance
A distance to jump.
CallbackDecl Callback
A C++ callback function to invoke.
Program * NestedProgram
The nested virtual machine program to invoke.