44#pragma GCC diagnostic push
45#pragma GCC diagnostic ignored "-Wunused-variable"
46#pragma GCC diagnostic ignored "-Wsign-compare"
49#include <libeval_compiler/grammar.c>
50#include <libeval_compiler/grammar.h>
53#pragma GCC diagnostic pop
57#define libeval_dbg(level, fmt, ...) \
58 wxLogTrace( "libeval_compiler", fmt, __VA_ARGS__ );
70 t2->
leaf[0] =
nullptr;
71 t2->
leaf[1] =
nullptr;
112 for(
int i = 0; simpleOps[i].op >= 0; i++ )
114 if( simpleOps[i].op == op )
115 return simpleOps[i].mnemonic;
162 str = wxString::Format(
"PUSH VAR [%p]",
m_ref.get() );
167 str = wxString::Format(
"PUSH nullptr" );
169 str = wxString::Format(
"PUSH NUM [%.10f]",
m_value->AsDouble() );
171 str = wxString::Format(
"PUSH STR [%ls]",
m_value->AsString() );
175 str = wxString::Format(
"MCALL" );
179 str = wxString::Format(
"FCALL" );
243 while( p <
m_str.length() && cond(
m_str[p] ) )
245 rv.append( 1,
m_str[p] );
254 const std::function<
bool( wxUniChar )>& stopCond )
const
258 if( remaining < (
int) match.length() )
261 if(
m_str.substr(
m_pos, match.length() ) == match )
262 return ( remaining == (
int) match.length() || stopCond(
m_str[
m_pos + match.length()] ) );
275 m_parser = LIBEVAL::ParseAlloc( malloc );
283 LIBEVAL::ParseFree(
m_parser, free );
350 libeval_dbg(0,
"str: '%s' empty: %d\n", aString.c_str(), !!aString.empty() );
352 if( aString.empty() )
379 }
while( tok.
token );
422 aToken.
token = G_STRING;
434 for(
const wxString& unitName :
m_unitResolver->GetSupportedUnits() )
439 return !isalnum( c );
442 libeval_dbg(10,
"Match unit '%s'\n", unitName.c_str() );
464 retval.
token = G_ENDS;
472 auto isDecimalSeparator =
473 [&]( wxUniChar ch ) ->
bool
482 bool haveSeparator =
false;
487 if( isDecimalSeparator( ch ) && haveSeparator )
490 current.append( 1, ch );
492 if( isDecimalSeparator( ch ) )
493 haveSeparator =
true;
497 }
while( isdigit( ch ) || isDecimalSeparator( ch ) );
500 for(
int i = current.length(); i; i-- )
502 if( isDecimalSeparator( current[i - 1] ) )
526 else if( isdigit( ch ) )
530 retval.
token = G_VALUE;
531 retval.
value.
str =
new wxString( current );
541 retval.
token = G_UNIT;
544 else if( ch ==
'\'' )
550 else if( isalpha( ch ) || ch ==
'_' )
552 current =
m_tokenizer.GetChars( [](
int c ) ->
bool {
return isalnum( c ) || c ==
'_'; } );
553 retval.
token = G_IDENTIFIER;
554 retval.
value.
str =
new wxString( current );
557 else if(
m_tokenizer.MatchAhead(
"==", [](
int c ) ->
bool { return c !=
'='; } ) )
559 retval.
token = G_EQUAL;
562 else if(
m_tokenizer.MatchAhead(
"!=", [](
int c ) ->
bool { return c !=
'='; } ) )
564 retval.
token = G_NOT_EQUAL;
567 else if(
m_tokenizer.MatchAhead(
"<=", [](
int c ) ->
bool { return c !=
'='; } ) )
569 retval.
token = G_LESS_EQUAL_THAN;
572 else if(
m_tokenizer.MatchAhead(
">=", [](
int c ) ->
bool { return c !=
'='; } ) )
574 retval.
token = G_GREATER_EQUAL_THAN;
577 else if(
m_tokenizer.MatchAhead(
"&&", [](
int c ) ->
bool { return c !=
'&'; } ) )
579 retval.
token = G_BOOL_AND;
582 else if(
m_tokenizer.MatchAhead(
"||", [](
int c ) ->
bool { return c !=
'|'; } ) )
584 retval.
token = G_BOOL_OR;
592 case '+': retval.
token = G_PLUS;
break;
593 case '!': retval.
token = G_BOOL_NOT;
break;
594 case '-': retval.
token = G_MINUS;
break;
595 case '*': retval.
token = G_MULT;
break;
596 case '/': retval.
token = G_DIVIDE;
break;
597 case '<': retval.
token = G_LESS_THAN;
break;
598 case '>': retval.
token = G_GREATER_THAN;
break;
599 case '(': retval.
token = G_PARENL;
break;
600 case ')': retval.
token = G_PARENR;
break;
601 case ';': retval.
token = G_SEMCOL;
break;
602 case '.': retval.
token = G_STRUCT_REF;
break;
603 case ',': retval.
token = G_COMMA;
break;
606 if(
m_tokenizer.MatchAhead(
"${", [](
int c ) ->
bool { return c !=
'{'; } ) )
634 str.Printf(
"\n[%p L0:%-20p L1:%-20p] ", tok, tok->
leaf[0], tok->
leaf[1] );
637 for(
int i = 0; i < 2 * depth; i++ )
693 str.Printf(
"UNIT: %d ", tok->
value.
idx );
745 std::unique_ptr<VALUE> val = std::make_unique<VALUE>( aValue );
746 val->SetUnits( aUnits );
747 uop =
new UOP( aOp, std::move( val ) );
755 std::unique_ptr<VALUE> val = std::make_unique<VALUE>( aValue, aStringIsWildcard );
756 uop =
new UOP( aOp, std::move( val ) );
764 uop =
new UOP( aOp, std::move( aRef ) );
772 uop =
new UOP( aOp, std::move( aFunc ), std::move( aRef ) );
798 std::vector<TREE_NODE*> args;
805 args.push_back( root );
813 args.push_back(n->
leaf[1]);
822 std::reverse( args.begin(), args.end() );
824 for(
size_t i = 0; i < args.size(); i++ )
864 std::vector<TREE_NODE*> stack;
866 int numericValueCount = 0;
867 wxString missingUnitsMsg;
868 int missingUnitsSrcPos = 0;
872 std::map<TREE_NODE*, UOP*> scJumps;
876 std::unique_ptr<VALUE> val = std::make_unique<VALUE>( 1.0 );
884 stack.push_back(
m_tree );
891 while( !stack.empty() )
895 libeval_dbg( 4,
"process node %p [op %d] [stack %lu]\n", node, node->
op, (
unsigned long)stack.size() );
937 switch( node->
leaf[1]->
op )
945 std::unique_ptr<VAR_REF> vref = aCode->
CreateVarRef( itemName, propName );
949 msg.Printf(
_(
"Unrecognized item '%s'" ), itemName );
954 msg.Printf(
_(
"Unrecognized property '%s'" ), propName );
971 std::unique_ptr<VAR_REF> vref = aCode->
CreateVarRef( itemName,
"" );
975 msg.Printf(
_(
"Unrecognized item '%s'" ), itemName );
983 libeval_dbg( 10,
"emit func call: %s\n", functionName );
987 msg.Printf(
_(
"Unrecognized function '%s'" ), functionName );
999 aPreflightContext->
Push( param );
1003 [&](
const wxString& aMessage,
int aOffset )
1011 func( aPreflightContext, vref.get() );
1012 aPreflightContext->
Pop();
1028 stack.push_back( node->
leaf[1] );
1031 stack.push_back( pnode );
1043 std::unique_ptr<VAR_REF> vref = aCode->
CreateVarRef( itemName, propName );
1047 msg.Printf(
_(
"Unrecognized item '%s'" ), itemName );
1051 msg.Printf(
_(
"Unrecognized property '%s'" ), propName );
1079 msg.Printf(
_(
"Unexpected units for '%s'" ),
formatNode( node ) );
1092 missingUnitsMsg.Printf(
_(
"Missing units for '%s'| (%s)" ),
1095 missingUnitsSrcPos = node->
srcPos;
1103 numericValueCount++;
1110 bool isWildcard = str.Contains(
"?") || str.Contains(
"*");
1122 msg.Printf(
_(
"Unrecognized item '%s'" ),
formatNode( node ) );
1142 stack.push_back( node->
leaf[0] );
1153 aCode->
AddOp( jump );
1155 scJumps[node] = jump;
1158 stack.push_back( node->
leaf[1] );
1170 node->
uop =
nullptr;
1173 auto jumpIt = scJumps.find( node );
1175 if( jumpIt != scJumps.end() )
1176 jumpIt->second->SetJumpTarget( aCode->
GetSize() );
1190 if( !missingUnitsMsg.IsEmpty() && numericValueCount == 1 )
1235 VALUE* value =
nullptr;
1273#define AS_DOUBLE( arg ) ( arg ? arg->AsDouble() : 0.0 )
1285 ctx->
ReportError( wxString::Format(
_(
"Type mismatch between '%s' and %lf" ),
1291 ctx->
ReportError( wxString::Format(
_(
"Type mismatch between %lf and '%s'" ),
1301 auto getOpResultUnits =
1308 return aVal2->GetUnits();
1313 return aVal2->GetUnits();
1322 resultUnits = getOpResultUnits( arg1, arg2 );
1327 resultUnits = getOpResultUnits( arg1, arg2 );
1332 resultUnits = getOpResultUnits( arg1, arg2 );
1337 resultUnits = getOpResultUnits( arg1, arg2 );
1356 if( !arg1 || !arg2 )
1357 result = arg1 == arg2 ? 1 : 0;
1365 if( !arg1 || !arg2 )
1366 result = arg1 != arg2 ? 1 : 0;
1395 double ARG1VALUE = arg1 ? arg1->
AsDouble() : 0.0;
1402 result = ARG1VALUE != 0.0 ? 0 : 1;
1405 result = ARG1VALUE != 0.0 ? 1 : 0;
1426 for( std::size_t ip = 0; ip <
m_ucode.size(); )
1432 wxASSERT(
next < 0 ||
static_cast<std::size_t
>(
next ) > ip );
1449 if( ctx->
SP() == 1 )
1459 wxASSERT( ctx->
SP() == 1 );
std::unique_ptr< UNIT_RESOLVER > m_unitResolver
void newString(const wxString &aString)
void freeTree(LIBEVAL::TREE_NODE *tree)
bool lexString(T_TOKEN &aToken)
void GcItem(TREE_NODE *aItem)
bool generateUCode(UCODE *aCode, CONTEXT *aPreflightContext)
char m_localeDecimalSeparator
std::function< void(const wxString &aMessage, int aOffset)> m_errorCallback
bool lexDefault(T_TOKEN &aToken)
std::vector< TREE_NODE * > m_gcItems
void reportError(COMPILATION_STAGE stage, const wxString &aErrorMsg, int aPos=-1)
void setRoot(LIBEVAL::TREE_NODE *root)
std::vector< wxString * > m_gcStrings
bool Compile(const wxString &aString, UCODE *aCode, CONTEXT *aPreflightContext)
ERROR_STATUS m_errorStatus
void parseError(const char *s)
VALUE * StoreValue(VALUE *aValue)
void ReportError(const wxString &aErrorMsg)
std::function< void(const wxString &aMessage, int aOffset)> m_errorCallback
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
VALUE * Top()
Peek the top of the stack without popping (used by the short-circuit jumps).
wxString GetChars(const std::function< bool(wxUniChar)> &cond) const
bool MatchAhead(const wxString &match, const std::function< bool(wxUniChar)> &stopCond) const
void SetUop(int aOp, double aValue, EDA_UNITS aUnits)
virtual std::unique_ptr< VAR_REF > CreateVarRef(const wxString &var, const wxString &field)
std::vector< UOP * > m_ucode
void MarkHasJumps()
Flag that this ucode contains short-circuit jumps, so Run() uses the jump-aware loop.
int GetSize() const
Index of the next op to be added (used to backpatch short-circuit jump targets).
VALUE * Run(CONTEXT *ctx)
virtual FUNC_CALL_REF CreateFuncCall(const wxString &name)
std::unique_ptr< VAR_REF > m_ref
int Exec(CONTEXT *ctx)
Execute the op.
std::unique_ptr< VALUE > m_value
virtual const wxString & AsString() const
void SetUnits(const EDA_UNITS aUnits)
virtual bool NotEqualTo(CONTEXT *aCtx, const VALUE *b) const
virtual double AsDouble() const
EDA_UNITS GetUnits() const
VAR_TYPE_T GetType() const
virtual bool EqualTo(CONTEXT *aCtx, const VALUE *b) const
#define libeval_dbg(level, fmt,...)
#define TR_OP_GREATER_EQUAL
#define TR_UOP_PUSH_VALUE
#define TR_OP_METHOD_CALL
#define TR_OP_BINARY_MASK
KICOMMON_API double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue to a double.
TREE_NODE * newNode(LIBEVAL::COMPILER *compiler, int op, const T_TOKEN_VALUE &value)
static bool flattenVarChain(TREE_NODE *aNode, wxString &aResult)
static std::vector< TREE_NODE * > squashParamList(TREE_NODE *root)
constexpr T_TOKEN defaultToken
void dumpNode(wxString &buf, TREE_NODE *tok, int depth=0)
static const VALUE g_shortCircuitFalse(0.0)
constexpr T_TOKEN_VALUE defaultTokenValue
std::function< void(CONTEXT *, void *)> FUNC_CALL_REF
static const wxString formatOpName(int op)
static const VALUE g_shortCircuitTrue(1.0)
const wxString formatNode(TREE_NODE *node)
static void prepareTree(LIBEVAL::TREE_NODE *node)
bool WildCompareString(const wxString &pattern, const wxString &string_to_tst, bool case_sensitive)
Compare a string against wild card (* and ?) pattern using the usual rules.
@ VALUE
Field Value of part, i.e. "3.3K".
wxString result
Test unit parsing edge cases and error handling.
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.