diff --git a/common/libeval_compiler/libeval_compiler.cpp b/common/libeval_compiler/libeval_compiler.cpp index ae3afb1430..1a1be7a449 100644 --- a/common/libeval_compiler/libeval_compiler.cpp +++ b/common/libeval_compiler/libeval_compiler.cpp @@ -138,6 +138,14 @@ std::string UCODE::Dump() const return rv; }; + +void CONTEXT::ReportError( const wxString& aErrorMsg ) +{ + m_errorStatus.pendingError = true; + m_errorStatus.message = aErrorMsg; +} + + std::string TOKENIZER::GetChars( std::function cond ) const { std::string rv; @@ -167,7 +175,6 @@ bool TOKENIZER::MatchAhead( const std::string& match, std::function COMPILER::COMPILER() { - m_errorStatus.pendingError = false; m_localeDecimalSeparator = '.'; m_sourcePos = 0; m_parseFinished = false; @@ -578,12 +585,7 @@ void dumpNode( std::string& buf, TREE_NODE* tok, int depth = 0 ) } } -ERROR_STATUS COMPILER::GetErrorStatus() -{ - return m_errorStatus; -} - -void COMPILER::ReportError( const std::string& aErrorMsg ) +void COMPILER::ReportError( const wxString& aErrorMsg ) { m_errorStatus.pendingError = true; m_errorStatus.message = aErrorMsg; @@ -694,6 +696,28 @@ bool COMPILER::generateUCode( UCODE* aCode ) return false; } + // Preflight the function call + CONTEXT ctx; + VALUE* param = ctx.AllocValue(); + param->Set( node->value.str ); + ctx.Push( param ); + + try + { + func( aCode, &ctx, vref ); + } + catch( ... ) + { + } + + if( ctx.GetErrorStatus().pendingError ) + { + m_errorStatus = ctx.GetErrorStatus(); + m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN; + m_errorStatus.srcPos = node->leaf[1]->leaf[0]->srcPos + 1; + return false; + } + visitedNodes.insert( node->leaf[0] ); visitedNodes.insert( node->leaf[1]->leaf[0] ); @@ -764,7 +788,7 @@ bool COMPILER::generateUCode( UCODE* aCode ) } -void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode ) +void UOP::Exec( CONTEXT* ctx, UCODE* ucode ) { switch( m_op ) @@ -772,7 +796,7 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode ) case TR_UOP_PUSH_VAR: { auto value = ctx->AllocValue(); - value->Set( reinterpret_cast( m_arg )->GetValue( ucode ) ); + value->Set( reinterpret_cast( m_arg )->GetValue( ctx, ucode ) ); ctx->Push( value ); } break; @@ -869,9 +893,4 @@ VALUE* UCODE::Run() } -void UCODE::RuntimeError( const std::string& aErrorMsg ) -{ - -} - } // namespace LIBEVAL diff --git a/include/libeval_compiler/libeval_compiler.h b/include/libeval_compiler/libeval_compiler.h index cf2c73eb4d..6e64ed4623 100644 --- a/include/libeval_compiler/libeval_compiler.h +++ b/include/libeval_compiler/libeval_compiler.h @@ -57,7 +57,7 @@ class COMPILER; struct ERROR_STATUS { - bool pendingError; + bool pendingError = false; enum STAGE { @@ -242,63 +242,69 @@ private: class UCODE; +class CONTEXT; + class VAR_REF { public: virtual VAR_TYPE_T GetType() = 0; - virtual VALUE GetValue( UCODE* aUcode ) = 0; + virtual VALUE GetValue( CONTEXT* aCtx, UCODE* aUcode ) = 0; +}; + + +class CONTEXT +{ +public: + const int c_memSize = 128; + + CONTEXT() + { + m_sp = 0; + + for( int i = 0; i < c_memSize; i++ ) + m_heap.emplace_back( VALUE() ); + } + + VALUE* AllocValue() + { + assert( m_memPos < c_memSize ); + auto rv = &m_heap[ m_memPos++ ]; + return rv; + } + + void Push( VALUE* v ) + { + m_stack[m_sp++] = v; + } + + VALUE* Pop() + { + m_sp--; + return m_stack[m_sp]; + } + + int SP() const + { + return m_sp; + } + + ERROR_STATUS GetErrorStatus() const { return m_errorStatus; } + void ReportError( const wxString& aErrorMsg ); + +private: + std::vector m_heap; + VALUE* m_stack[128]; + int m_sp = 0; + int m_memPos = 0; + ERROR_STATUS m_errorStatus; }; class UCODE { public: - - class CONTEXT - { - public: - const int c_memSize = 128; - - CONTEXT() - { - m_sp = 0; - - for( int i = 0; i < c_memSize; i++ ) - m_memory.push_back( VALUE() ); - } - - VALUE* AllocValue() - { - assert( m_memPos < c_memSize ); - auto rv = &m_memory[ m_memPos++ ]; - return rv; - } - - void Push( VALUE* v ) - { - m_stack[m_sp++] = v; - } - - VALUE* Pop() - { - m_sp--; - return m_stack[m_sp]; - } - - int SP() const - { - return m_sp; - } - - private: - std::vector m_memory; - VALUE* m_stack[128]; - int m_sp = 0; - int m_memPos = 0; - }; - - typedef std::function FUNC_PTR; + typedef std::function FUNC_PTR; void AddOp( UOP* uop ) { @@ -307,9 +313,9 @@ public: VALUE* Run(); std::string Dump() const; - void RuntimeError( const std::string& aErrorMsg ); - virtual VAR_REF* createVarRef( COMPILER* aCompiler, const std::string& var, const std::string& field ) + virtual VAR_REF* createVarRef( COMPILER* aCompiler, const std::string& var, + const std::string& field ) { return nullptr; }; @@ -338,7 +344,7 @@ public: m_func( std::move( func ) ) {}; - void Exec( UCODE::CONTEXT* ctx, UCODE *ucode ); + void Exec( CONTEXT* ctx, UCODE *ucode ); std::string Format() const; @@ -423,8 +429,8 @@ public: void setRoot( LIBEVAL::TREE_NODE root ); bool Compile( const std::string& aString, UCODE* aCode ); - void ReportError( const std::string& aErrorMsg ); - ERROR_STATUS GetErrorStatus(); + void ReportError( const wxString& aErrorMsg ); + ERROR_STATUS GetErrorStatus() const { return m_errorStatus; } protected: enum LEXER_STATE diff --git a/pcbnew/drc/drc_rule.cpp b/pcbnew/drc/drc_rule.cpp index 35511f3458..22dbdd50d2 100644 --- a/pcbnew/drc/drc_rule.cpp +++ b/pcbnew/drc/drc_rule.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -75,16 +74,6 @@ * (rule "disallowMicrovias" (disallow micro_via)) * * - testEvalExpr( "A.type == \"Pad\" && B.type == \"Pad\" && (A.onLayer(\"F.Cu\"))",VAL(0.0), false, &trackA, &trackB ); - return 0; - testEvalExpr( "A.Width > B.Width", VAL(0.0), false, &trackA, &trackB ); - testEvalExpr( "A.Width + B.Width", VAL(Mils2iu(10) + Mils2iu(20)), false, &trackA, &trackB ); - - testEvalExpr( "A.Netclass", VAL( (const char*) trackA.GetNetClassName().c_str() ), false, &trackA, &trackB ); - testEvalExpr( "(A.Netclass == \"HV\") && (B.netclass == \"otherClass\") && (B.netclass != \"F.Cu\")", VAL( 1.0 ), false, &trackA, &trackB ); - testEvalExpr( "A.Netclass + 1.0", VAL( 1.0 ), false, &trackA, &trackB ); - testEvalExpr( "A.type == \"Track\" && B.type == \"Track\" && A.layer == \"F.Cu\"", VAL(0.0), false, &trackA, &trackB ); - testEvalExpr( "(A.type == \"Track\") && (B.type == \"Track\") && (A.layer == \"F.Cu\")", VAL(0.0), false, &trackA, &trackB ); */ DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint ) @@ -126,7 +115,6 @@ bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM m_ucode->SetItems( a, b ); -// fixme: handle error conditions return m_ucode->Run()->AsDouble() != 0.0; } diff --git a/pcbnew/pcb_expr_evaluator.cpp b/pcbnew/pcb_expr_evaluator.cpp index f70f066945..baf5c3927d 100644 --- a/pcbnew/pcb_expr_evaluator.cpp +++ b/pcbnew/pcb_expr_evaluator.cpp @@ -62,33 +62,49 @@ public: private: std::map m_funcs; - static void onLayer( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self ) + static void onLayer( LIBEVAL::UCODE* aUcode, LIBEVAL::CONTEXT* aCtx, void *self ) { - LIBEVAL::VALUE* arg = aCtx->Pop(); - PCB_EXPR_VAR_REF* vref = static_cast( self ); - PCB_LAYER_ID layer = ENUM_MAP::Instance().ToEnum( arg->AsString() ); - BOARD_ITEM* item = vref->GetObject( aUcode ); - LIBEVAL::VALUE* rv = aCtx->AllocValue(); + LIBEVAL::VALUE* arg = aCtx->Pop(); + LIBEVAL::VALUE* result = aCtx->AllocValue(); - rv->Set( item->IsOnLayer( layer ) ? 1.0 : 0.0 ); - aCtx->Push( rv ); - } + result->Set( 0.0 ); + aCtx->Push( result ); - static void isPlated( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self ) - { - PCB_EXPR_VAR_REF* vref = static_cast( self ); - BOARD_ITEM* item = vref->GetObject( aUcode ); - bool result = false; - - if( item->Type() == PCB_PAD_T ) + if( !arg ) { - D_PAD* pad = static_cast( item ); - result = pad->GetAttribute() == PAD_ATTRIB_STANDARD; + aCtx->ReportError( _( "Missing argument to 'onLayer()'" ) ); + return; } - LIBEVAL::VALUE* rv = aCtx->AllocValue(); - rv->Set( result ? 1.0 : 0.0 ); - aCtx->Push( rv ); + wxString layerName = arg->AsString(); + PCB_LAYER_ID layer = ENUM_MAP::Instance().ToEnum( layerName ); + + if( layer == UNDEFINED_LAYER ) + { + aCtx->ReportError( wxString::Format( _( "Unrecognized layer '%s' " ), layerName ) ); + return; + } + + PCB_EXPR_VAR_REF* vref = static_cast( self ); + BOARD_ITEM* item = vref ? vref->GetObject( aUcode ) : nullptr; + + if( item && item->IsOnLayer( layer ) ) + result->Set( 1.0 ); + } + + static void isPlated( LIBEVAL::UCODE* aUcode, LIBEVAL::CONTEXT* aCtx, void *self ) + { + LIBEVAL::VALUE* result = aCtx->AllocValue(); + + result->Set( 0.0 ); + aCtx->Push( result ); + + PCB_EXPR_VAR_REF* vref = static_cast( self ); + BOARD_ITEM* item = vref ? vref->GetObject( aUcode ) : nullptr; + D_PAD* pad = dynamic_cast( item ); + + if( pad && pad->GetAttribute() == PAD_ATTRIB_STANDARD ) + result->Set( 1.0 ); } }; @@ -108,7 +124,7 @@ BOARD_ITEM* PCB_EXPR_VAR_REF::GetObject( LIBEVAL::UCODE* aUcode ) const } -LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode ) +LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx, LIBEVAL::UCODE* aUcode ) { BOARD_ITEM* item = const_cast( GetObject( aUcode ) ); auto it = m_matchingTypes.find( TYPE_HASH( *item ) ); @@ -117,7 +133,7 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode ) { wxString msg; msg.Printf("property not found for item of type: 0x%x!\n", TYPE_HASH( *item ) ); - aUcode->RuntimeError( (const char *) msg.c_str() ); + aCtx->ReportError( (const char *) msg.c_str() ); return LIBEVAL::VALUE( 0.0 ); } else @@ -261,7 +277,6 @@ PCB_EXPR_COMPILER::PCB_EXPR_COMPILER() PCB_EXPR_EVALUATOR::PCB_EXPR_EVALUATOR() { m_result = 0; - m_errorStatus.pendingError = false; } PCB_EXPR_EVALUATOR::~PCB_EXPR_EVALUATOR() diff --git a/pcbnew/pcb_expr_evaluator.h b/pcbnew/pcb_expr_evaluator.h index d5a2f40314..9fd5b442de 100644 --- a/pcbnew/pcb_expr_evaluator.h +++ b/pcbnew/pcb_expr_evaluator.h @@ -90,7 +90,7 @@ public: return m_type; } - virtual LIBEVAL::VALUE GetValue( LIBEVAL::UCODE* aUcode ) override; + virtual LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx, LIBEVAL::UCODE* aUcode ) override; BOARD_ITEM* GetObject( LIBEVAL::UCODE* aUcode ) const; diff --git a/qa/drc_proto/drc_rule.cpp b/qa/drc_proto/drc_rule.cpp index c321e78a48..9611784217 100644 --- a/qa/drc_proto/drc_rule.cpp +++ b/qa/drc_proto/drc_rule.cpp @@ -23,12 +23,9 @@ #include -#include +#include #include #include - - -#include #include @@ -56,9 +53,11 @@ test::DRC_RULE_CONDITION::~DRC_RULE_CONDITION() bool test::DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB ) { - m_ucode->SetItems( const_cast( aItemA ), const_cast( aItemB ) ); + BOARD_ITEM* a = const_cast( aItemA ); + BOARD_ITEM* b = aItemB ? const_cast( aItemB ) : DELETED_BOARD_ITEM::GetInstance(); + + m_ucode->SetItems( a, b ); -// fixme: handle error conditions return m_ucode->Run()->AsDouble() != 0.0; } @@ -77,8 +76,6 @@ bool test::DRC_RULE_CONDITION::Compile() m_compileError = compiler.GetErrorStatus(); - printf( "Fail: %s", m_compileError.Format().c_str() ); - return false; }