From ec92def53979e4f1bb14ab4a7be4f7bd13cb0eb4 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Tue, 29 Nov 2022 14:18:44 +0000 Subject: [PATCH] Add support for unitless values to PCB_EXPR_EVALUATOR. Fixes https://gitlab.com/kicad/code/kicad/issues/13016 (cherry picked from commit 8260f0ee13b777eae203e5ea88cfa586ef06a9de) --- common/libeval_compiler/libeval_compiler.cpp | 11 ++- pcbnew/drc/drc_rule_condition.cpp | 2 +- pcbnew/drc/drc_rule_parser.cpp | 14 ++-- pcbnew/drc/drc_rule_parser.h | 2 +- pcbnew/pcb_expr_evaluator.cpp | 82 ++++++++++--------- pcbnew/pcb_expr_evaluator.h | 24 +++++- qa/libeval_compiler/libeval_compiler_test.cpp | 5 +- qa/pcbnew/test_libeval_compiler.cpp | 2 +- 8 files changed, 89 insertions(+), 53 deletions(-) diff --git a/common/libeval_compiler/libeval_compiler.cpp b/common/libeval_compiler/libeval_compiler.cpp index b059230130..1f42e7e6c0 100644 --- a/common/libeval_compiler/libeval_compiler.cpp +++ b/common/libeval_compiler/libeval_compiler.cpp @@ -1008,10 +1008,13 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) } else { - msg.Printf( _( "Missing units for '%s'| (%s)" ), - *node->value.str, - m_unitResolver->GetSupportedUnitsMessage() ); - reportError( CST_CODEGEN, msg, node->srcPos ); + if( !m_unitResolver->GetSupportedUnitsMessage().empty() ) + { + msg.Printf( _( "Missing units for '%s'| (%s)" ), + *node->value.str, + m_unitResolver->GetSupportedUnitsMessage() ); + reportError( CST_CODEGEN, msg, node->srcPos ); + } value = DoubleValueFromString( EDA_UNITS::UNSCALED, *node->value.str ); } diff --git a/pcbnew/drc/drc_rule_condition.cpp b/pcbnew/drc/drc_rule_condition.cpp index 947d16df4f..6dce18eee4 100644 --- a/pcbnew/drc/drc_rule_condition.cpp +++ b/pcbnew/drc/drc_rule_condition.cpp @@ -88,7 +88,7 @@ bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM bool DRC_RULE_CONDITION::Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset ) { - PCB_EXPR_COMPILER compiler; + PCB_EXPR_COMPILER compiler( new PCB_UNIT_RESOLVER() ); if( aReporter ) { diff --git a/pcbnew/drc/drc_rule_parser.cpp b/pcbnew/drc/drc_rule_parser.cpp index 355a1899ea..4c9eaab2e6 100644 --- a/pcbnew/drc/drc_rule_parser.cpp +++ b/pcbnew/drc/drc_rule_parser.cpp @@ -297,6 +297,8 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) reportError( msg ); } + bool unitless = c.m_Type == VIA_COUNT_CONSTRAINT; + if( c.m_Type == DISALLOW_CONSTRAINT ) { for( token = NextTok(); token != T_RIGHT; token = NextTok() ) @@ -355,7 +357,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) break; } - parseValueWithUnits( FromUTF8(), value ); + parseValueWithUnits( FromUTF8(), value, unitless ); c.m_Value.SetMin( value ); if( (int) NextTok() != DSN_RIGHT ) @@ -375,7 +377,8 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) break; } - parseValueWithUnits( FromUTF8(), value ); + parseValueWithUnits( FromUTF8(), value, unitless ); + c.m_Value.SetMax( value ); if( (int) NextTok() != DSN_RIGHT ) @@ -395,7 +398,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) break; } - parseValueWithUnits( FromUTF8(), value ); + parseValueWithUnits( FromUTF8(), value, unitless ); c.m_Value.SetOpt( value ); if( (int) NextTok() != DSN_RIGHT ) @@ -426,7 +429,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) } -void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult ) +void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult, bool aUnitless ) { auto errorHandler = [&]( const wxString& aMessage, int aOffset ) { @@ -449,7 +452,8 @@ void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult } }; - PCB_EXPR_EVALUATOR evaluator; + PCB_EXPR_EVALUATOR evaluator( aUnitless ? (LIBEVAL::UNIT_RESOLVER*) new PCB_UNITLESS_RESOLVER() + : (LIBEVAL::UNIT_RESOLVER*) new PCB_UNIT_RESOLVER() ); evaluator.SetErrorCallback( errorHandler ); evaluator.Evaluate( aExpr ); diff --git a/pcbnew/drc/drc_rule_parser.h b/pcbnew/drc/drc_rule_parser.h index 19dfa2abde..d3d6512bc7 100644 --- a/pcbnew/drc/drc_rule_parser.h +++ b/pcbnew/drc/drc_rule_parser.h @@ -49,7 +49,7 @@ private: DRC_RULE* parseDRC_RULE(); void parseConstraint( DRC_RULE* aRule ); - void parseValueWithUnits( const wxString& aExpr, int& aResult ); + void parseValueWithUnits( const wxString& aExpr, int& aResult, bool aUnitless = false ); LSET parseLayer(); void parseUnknown(); diff --git a/pcbnew/pcb_expr_evaluator.cpp b/pcbnew/pcb_expr_evaluator.cpp index e4c896bc78..1652c23c26 100644 --- a/pcbnew/pcb_expr_evaluator.cpp +++ b/pcbnew/pcb_expr_evaluator.cpp @@ -1144,49 +1144,57 @@ BOARD* PCB_EXPR_CONTEXT::GetBoard() const } -class PCB_UNIT_RESOLVER : public LIBEVAL::UNIT_RESOLVER +const std::vector& PCB_UNIT_RESOLVER::GetSupportedUnits() const { -public: - virtual ~PCB_UNIT_RESOLVER() - { - } + static const std::vector pcbUnits = { wxT( "mil" ), wxT( "mm" ), wxT( "in" ) }; - virtual const std::vector& GetSupportedUnits() const override - { - static const std::vector pcbUnits = { wxT( "mil" ), wxT( "mm" ), wxT( "in" ) }; - - return pcbUnits; - } - - virtual wxString GetSupportedUnitsMessage() const override - { - return _( "must be mm, in, or mil" ); - } - - virtual double Convert( const wxString& aString, int unitId ) const override - { - double v = wxAtof( aString ); - - switch( unitId ) - { - case 0: return DoubleValueFromString( EDA_UNITS::MILS, aString ); - case 1: return DoubleValueFromString( EDA_UNITS::MILLIMETRES, aString ); - case 2: return DoubleValueFromString( EDA_UNITS::INCHES, aString ); - default: return v; - } - }; -}; - - -PCB_EXPR_COMPILER::PCB_EXPR_COMPILER() -{ - m_unitResolver = std::make_unique(); + return pcbUnits; } -PCB_EXPR_EVALUATOR::PCB_EXPR_EVALUATOR() : +wxString PCB_UNIT_RESOLVER::GetSupportedUnitsMessage() const +{ + return _( "must be mm, in, or mil" ); +} + + +double PCB_UNIT_RESOLVER::Convert( const wxString& aString, int unitId ) const +{ + double v = wxAtof( aString ); + + switch( unitId ) + { + case 0: return DoubleValueFromString( EDA_UNITS::MILS, aString ); + case 1: return DoubleValueFromString( EDA_UNITS::MILLIMETRES, aString ); + case 2: return DoubleValueFromString( EDA_UNITS::INCHES, aString ); + default: return v; + } +}; + + +const std::vector& PCB_UNITLESS_RESOLVER::GetSupportedUnits() const +{ + static const std::vector emptyUnits; + + return emptyUnits; +} + + +double PCB_UNITLESS_RESOLVER::Convert( const wxString& aString, int unitId ) const +{ + return wxAtof( aString ); +}; + + +PCB_EXPR_COMPILER::PCB_EXPR_COMPILER( LIBEVAL::UNIT_RESOLVER* aUnitResolver ) +{ + m_unitResolver.reset( aUnitResolver ); +} + + +PCB_EXPR_EVALUATOR::PCB_EXPR_EVALUATOR( LIBEVAL::UNIT_RESOLVER* aUnitResolver ) : m_result( 0 ), - m_compiler(), + m_compiler( aUnitResolver ), m_ucode(), m_errorStatus() { diff --git a/pcbnew/pcb_expr_evaluator.h b/pcbnew/pcb_expr_evaluator.h index d9e110210e..aa3ad4a9e4 100644 --- a/pcbnew/pcb_expr_evaluator.h +++ b/pcbnew/pcb_expr_evaluator.h @@ -196,17 +196,37 @@ private: }; +class PCB_UNIT_RESOLVER : public LIBEVAL::UNIT_RESOLVER +{ +public: + const std::vector& GetSupportedUnits() const override; + + wxString GetSupportedUnitsMessage() const override; + + double Convert( const wxString& aString, int unitId ) const override; +}; + + +class PCB_UNITLESS_RESOLVER : public LIBEVAL::UNIT_RESOLVER +{ +public: + const std::vector& GetSupportedUnits() const override; + + double Convert( const wxString& aString, int unitId ) const override; +}; + + class PCB_EXPR_COMPILER : public LIBEVAL::COMPILER { public: - PCB_EXPR_COMPILER(); + PCB_EXPR_COMPILER( LIBEVAL::UNIT_RESOLVER* aUnitResolver ); }; class PCB_EXPR_EVALUATOR { public: - PCB_EXPR_EVALUATOR( ); + PCB_EXPR_EVALUATOR( LIBEVAL::UNIT_RESOLVER* aUnitResolver ); ~PCB_EXPR_EVALUATOR(); bool Evaluate( const wxString& aExpr ); diff --git a/qa/libeval_compiler/libeval_compiler_test.cpp b/qa/libeval_compiler/libeval_compiler_test.cpp index 6eadce5a69..4459a94e83 100644 --- a/qa/libeval_compiler/libeval_compiler_test.cpp +++ b/qa/libeval_compiler/libeval_compiler_test.cpp @@ -13,9 +13,10 @@ #include -bool testEvalExpr( const std::string expr, LIBEVAL::VALUE expectedResult, bool expectError = false, BOARD_ITEM* itemA = nullptr, BOARD_ITEM* itemB = nullptr ) +bool testEvalExpr( const std::string expr, LIBEVAL::VALUE expectedResult, bool expectError = false, + BOARD_ITEM* itemA = nullptr, BOARD_ITEM* itemB = nullptr ) { - PCB_EXPR_COMPILER compiler; + PCB_EXPR_COMPILER compiler( new PCB_UNIT_RESOLVER() ); PCB_EXPR_UCODE ucode; bool ok = true; diff --git a/qa/pcbnew/test_libeval_compiler.cpp b/qa/pcbnew/test_libeval_compiler.cpp index 007a8fcd80..7bfda3b0ed 100644 --- a/qa/pcbnew/test_libeval_compiler.cpp +++ b/qa/pcbnew/test_libeval_compiler.cpp @@ -89,7 +89,7 @@ static bool testEvalExpr( const wxString& expr, LIBEVAL::VALUE expectedResult, bool expectError = false, BOARD_ITEM* itemA = nullptr, BOARD_ITEM* itemB = nullptr ) { - PCB_EXPR_COMPILER compiler; + PCB_EXPR_COMPILER compiler( new PCB_UNIT_RESOLVER() ); PCB_EXPR_UCODE ucode; PCB_EXPR_CONTEXT context( NULL_CONSTRAINT, UNDEFINED_LAYER ); PCB_EXPR_CONTEXT preflightContext( NULL_CONSTRAINT, UNDEFINED_LAYER );