Add support for unitless values to PCB_EXPR_EVALUATOR.

Fixes https://gitlab.com/kicad/code/kicad/issues/13016

(cherry picked from commit 8260f0ee13)
This commit is contained in:
Jeff Young 2022-11-29 14:18:44 +00:00
parent 2dd04ea43a
commit ec92def539
8 changed files with 89 additions and 53 deletions

View File

@ -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 );
}

View File

@ -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 )
{

View File

@ -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 );

View File

@ -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();

View File

@ -1144,49 +1144,57 @@ BOARD* PCB_EXPR_CONTEXT::GetBoard() const
}
class PCB_UNIT_RESOLVER : public LIBEVAL::UNIT_RESOLVER
const std::vector<wxString>& PCB_UNIT_RESOLVER::GetSupportedUnits() const
{
public:
virtual ~PCB_UNIT_RESOLVER()
{
}
static const std::vector<wxString> pcbUnits = { wxT( "mil" ), wxT( "mm" ), wxT( "in" ) };
virtual const std::vector<wxString>& GetSupportedUnits() const override
{
static const std::vector<wxString> 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<PCB_UNIT_RESOLVER>();
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<wxString>& PCB_UNITLESS_RESOLVER::GetSupportedUnits() const
{
static const std::vector<wxString> 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()
{

View File

@ -196,17 +196,37 @@ private:
};
class PCB_UNIT_RESOLVER : public LIBEVAL::UNIT_RESOLVER
{
public:
const std::vector<wxString>& 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<wxString>& 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 );

View File

@ -13,9 +13,10 @@
#include <profile.h>
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;

View File

@ -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 );