From af5afb5dd79cd94f3a8e6a6ea8bc86f25dab42a0 Mon Sep 17 00:00:00 2001 From: Tomasz Wlostowski Date: Sun, 14 Jun 2020 01:22:08 +0200 Subject: [PATCH] pcbnew: initial version of PCB-specific expression evaluator --- common/CMakeLists.txt | 1 + pcbnew/pcb_expr_evaluator.cpp | 135 ++++++++++++++++++++++++++++++++++ pcbnew/pcb_expr_evaluator.h | 98 ++++++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 pcbnew/pcb_expr_evaluator.cpp create mode 100644 pcbnew/pcb_expr_evaluator.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index c6d9c7beed..227baabebb 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -449,6 +449,7 @@ set( PCB_COMMON_SRCS origin_viewitem.cpp page_info.cpp ${CMAKE_SOURCE_DIR}/pcbnew/pcb_base_frame.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/pcb_expr_evaluator.cpp ${CMAKE_SOURCE_DIR}/pcbnew/board_commit.cpp ${CMAKE_SOURCE_DIR}/pcbnew/board_connected_item.cpp ${CMAKE_SOURCE_DIR}/pcbnew/board_design_settings.cpp diff --git a/pcbnew/pcb_expr_evaluator.cpp b/pcbnew/pcb_expr_evaluator.cpp new file mode 100644 index 0000000000..7cdecd6241 --- /dev/null +++ b/pcbnew/pcb_expr_evaluator.cpp @@ -0,0 +1,135 @@ +#include + +#include "class_board.h" + +#include "pcb_expr_evaluator.h" + +LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode ) +{ + auto ucode = static_cast( aUcode ); + auto item = ucode->GetItem( m_itemIndex ); + + auto it = m_matchingTypes.find( TYPE_HASH( *item ) ); + + if( it == m_matchingTypes.end() ) + { + wxString msg; + msg.Printf("property not found for item of type: 0x%x!\n", TYPE_HASH( *item ) ); + aUcode->RuntimeError( (const char *) msg.c_str() ); + return LIBEVAL::VALUE( 0.0 ); + } + else + { + if( m_type == LIBEVAL::VT_NUMERIC ) + return LIBEVAL::VALUE( (double) item->Get( it->second ) ); + else + { + wxString str = item->Get( it->second ); + //printf("item %p GetStr '%s'\n", item, (const char*) str.c_str()); + return LIBEVAL::VALUE( (const char*) str.c_str() ); + } + } +} + +LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, + const std::string& var, const std::string& field ) +{ + PCB_EXPR_VAR_REF* rv; + + PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); + + auto classes = propMgr.GetAllClasses(); + auto vref = new PCB_EXPR_VAR_REF( var == "A" ? 0 : 1 ); + + for( auto cls : classes ) + { + if( propMgr.IsOfType( cls.type, TYPE_HASH( BOARD_ITEM ) ) ) + { + PROPERTY_BASE* prop = propMgr.GetProperty( cls.type, field ); + if( prop ) + { + //printf("Field '%s' class %s ptr %p\n", field.c_str(), (const char *) cls.name.c_str(), prop ); + vref->AddAllowedClass( cls.type, prop ); + if( prop->TypeHash() == TYPE_HASH( int ) ) + vref->SetType( LIBEVAL::VT_NUMERIC ); + else if( prop->TypeHash() == TYPE_HASH( wxString ) ) + vref->SetType( LIBEVAL::VT_STRING ); + else + { + printf( "Unknown property type\n" ); + } + } + } + } + + return vref; +} + + +class PCB_UNIT_RESOLVER : public LIBEVAL::UNIT_RESOLVER +{ +public: + virtual ~PCB_UNIT_RESOLVER() + { + } + + virtual const std::vector& GetSupportedUnits() const override + { + static const std::vector pcbUnits = { "mil", "mm", "in" }; + + return pcbUnits; + } + + virtual double Convert( const std::string aString, int unitId ) const override + { + double v = atof( aString.c_str() ); + switch( unitId ) + { + case 0: + return Mils2iu( v ); + case 1: + return Millimeter2iu( v ); + case 2: + return Mils2iu( v * 1000.0 ); + default: + return v; + } + }; +}; + + +PCB_EXPR_COMPILER::PCB_EXPR_COMPILER() +{ + m_unitResolver.reset( new PCB_UNIT_RESOLVER ); +} + + +PCB_EXPR_EVALUATOR::PCB_EXPR_EVALUATOR() +{ + m_error = false; +} + +PCB_EXPR_EVALUATOR::~PCB_EXPR_EVALUATOR() +{ +} + + +bool PCB_EXPR_EVALUATOR::Evaluate( const wxString& aExpr ) +{ + PCB_EXPR_UCODE ucode; + if( !m_compiler.Compile( (const char*) aExpr.c_str(), &ucode ) ) + return false; + + auto result = ucode.Run(); + + if( result->GetType() == LIBEVAL::VT_NUMERIC ) + m_result = KiROUND( result->AsDouble() ); + + return true; +} + +wxString PCB_EXPR_EVALUATOR::GetErrorString() +{ + wxString errMsg; + return errMsg; +} diff --git a/pcbnew/pcb_expr_evaluator.h b/pcbnew/pcb_expr_evaluator.h new file mode 100644 index 0000000000..9521de893d --- /dev/null +++ b/pcbnew/pcb_expr_evaluator.h @@ -0,0 +1,98 @@ +#ifndef __PCB_EXPR_EVALUATOR_H +#define __PCB_EXPR_EVALUATOR_H + +#include + +#include +#include + +#include + + +class BOARD_ITEM; + +class PCB_EXPR_VAR_REF; + +class PCB_EXPR_UCODE : public LIBEVAL::UCODE +{ +public: + virtual LIBEVAL::VAR_REF* createVarRef( LIBEVAL::COMPILER *aCompiler, + const std::string& var, const std::string& field ) override; + + void SetItems( BOARD_ITEM* a, BOARD_ITEM* b = nullptr ) + { + m_items[0] = a; + m_items[1] = b; + } + + BOARD_ITEM* GetItem( int index ) const + { + return m_items[index]; + } + +private: + BOARD_ITEM* m_items[2]; +}; + + +class PCB_EXPR_VAR_REF : public LIBEVAL::VAR_REF +{ +public: + PCB_EXPR_VAR_REF( int aItemIndex ) : m_itemIndex( aItemIndex ) + { + //printf("*** createVarRef %p %d\n", this, aItemIndex ); + } + + void SetType( LIBEVAL::VAR_TYPE_T type ) + { + m_type = type; + } + + void AddAllowedClass( TYPE_ID type_hash, PROPERTY_BASE* prop ) + { + m_matchingTypes[type_hash] = prop; + } + + virtual LIBEVAL::VAR_TYPE_T GetType( LIBEVAL::UCODE* aUcode ) override + { + return m_type; + } + + virtual LIBEVAL::VALUE GetValue( LIBEVAL::UCODE* aUcode ) override; + +private: + std::unordered_map m_matchingTypes; + int m_itemIndex; + LIBEVAL::VAR_TYPE_T m_type; +}; + + +class PCB_EXPR_COMPILER : public LIBEVAL::COMPILER +{ +public: + PCB_EXPR_COMPILER(); +}; + + +class PCB_EXPR_EVALUATOR +{ +public: + PCB_EXPR_EVALUATOR(); + ~PCB_EXPR_EVALUATOR(); + + bool Evaluate( const wxString& aExpr ); + int Result() const + { + return m_result; + } + wxString GetErrorString(); + +private: + bool m_error; + int m_result; + + PCB_EXPR_COMPILER m_compiler; + PCB_EXPR_UCODE m_ucode; +}; + +#endif