Better handling of undefined values in Rule expressions.

This is particularly important to keep the user from having to
enter overly verbose statements such as:
A.Type == 'via' && A.Via_Type == 'buried'
when:
A.Via_Type == 'buried'
is perfectly clear.
This commit is contained in:
Jeff Young 2020-07-23 11:35:05 +01:00
parent 84085df82a
commit f2812773d4
10 changed files with 46 additions and 37 deletions

View File

@ -744,9 +744,8 @@ static struct EDA_ITEM_DESC
EDA_ITEM_DESC()
{
ENUM_MAP<KICAD_T>::Instance()
.Undefined( TYPE_NOT_INIT )
.Map( NOT_USED, wxT( "<not used>" ) )
//.Map( EOT, wxT( "<EOT>" ) )
.Map( TYPE_NOT_INIT, wxT( "<type not init>" ) ) // == EOT
.Map( SCREEN_T, _( "Screen" ) )
.Map( PCB_MODULE_T, _( "Footprint" ) )
@ -799,9 +798,7 @@ static struct EDA_ITEM_DESC
.Map( GERBER_LAYOUT_T, _( "Gerber Layout" ) )
.Map( GERBER_DRAW_ITEM_T, _( "Draw Item" ) )
.Map( GERBER_IMAGE_T, _( "Image" ) )
.Map( MAX_STRUCT_TYPE_ID, wxT( "<max struct type>" ) );
.Map( GERBER_IMAGE_T, _( "Image" ) );
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
REGISTER_TYPE( EDA_ITEM );

View File

@ -787,7 +787,7 @@ void UOP::Exec( CONTEXT* ctx, UCODE* ucode )
case TR_UOP_PUSH_VAR:
{
auto value = ctx->AllocValue();
value->Set( reinterpret_cast<VAR_REF*>( m_arg )->GetValue( ctx, ucode ) );
value->Set( reinterpret_cast<VAR_REF*>( m_arg )->GetValue( ucode ) );
ctx->Push( value );
}
break;

View File

@ -249,7 +249,7 @@ class VAR_REF
{
public:
virtual VAR_TYPE_T GetType() = 0;
virtual VALUE GetValue( CONTEXT* aCtx, UCODE* aUcode ) = 0;
virtual VALUE GetValue( UCODE* aUcode ) = 0;
};

View File

@ -528,14 +528,22 @@ public:
return *this;
}
void SetDefault( T aValue )
ENUM_MAP& Undefined( T aValue )
{
m_default = aValue;
m_undefined = aValue;
return *this;
}
const wxString& ToString( T value ) const
{
static const wxString s_undef = "UNDEFINED";
int idx = static_cast<int>( value );
if( idx >= 0 && idx < (int) m_choices.GetCount() )
return m_choices.GetLabel( static_cast<int>( value ) );
else
return s_undef;
}
const T ToEnum( const wxString value )
@ -543,7 +551,7 @@ public:
if( m_reverseMap.count( value ) )
return m_reverseMap[ value ];
else
return m_default;
return m_undefined;
}
wxPGChoices& Choices()
@ -554,7 +562,7 @@ public:
private:
wxPGChoices m_choices;
std::unordered_map<wxString, T> m_reverseMap;
T m_default; // Returned if the string is not recognized
T m_undefined; // Returned if the string is not recognized
ENUM_MAP<T>()
{

View File

@ -208,7 +208,7 @@ static struct BOARD_CONNECTED_ITEM_DESC
if( layerEnum.Choices().GetCount() == 0 )
{
layerEnum.SetDefault( UNDEFINED_LAYER );
layerEnum.Undefined( UNDEFINED_LAYER );
for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
layerEnum.Map( *seq, LSET::Name( *seq ) );

View File

@ -147,7 +147,7 @@ static struct BOARD_ITEM_DESC
if( layerEnum.Choices().GetCount() == 0 )
{
layerEnum.SetDefault( UNDEFINED_LAYER );
layerEnum.Undefined( UNDEFINED_LAYER );
for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
layerEnum.Map( *seq, LSET::Name( *seq ) );

View File

@ -983,6 +983,7 @@ static struct TRACK_VIA_DESC
TRACK_VIA_DESC()
{
ENUM_MAP<VIATYPE>::Instance()
.Undefined( VIATYPE::NOT_DEFINED )
.Map( VIATYPE::THROUGH, _( "Through" ) )
.Map( VIATYPE::BLIND_BURIED, _( "Blind/Buried" ) )
.Map( VIATYPE::MICROVIA, _( "Microvia" ) );

View File

@ -470,7 +470,7 @@ void PCB_EDIT_FRAME::ReFillLayerWidget()
ENUM_MAP<PCB_LAYER_ID>& layerEnum = ENUM_MAP<PCB_LAYER_ID>::Instance();
layerEnum.Choices().Clear();
layerEnum.SetDefault( UNDEFINED_LAYER );
layerEnum.Undefined( UNDEFINED_LAYER );
for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
layerEnum.Map( *seq, GetBoard()->GetLayerName( *seq ) );

View File

@ -99,17 +99,18 @@ BOARD_ITEM* PCB_EXPR_VAR_REF::GetObject( LIBEVAL::UCODE* aUcode ) const
}
LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx, LIBEVAL::UCODE* aUcode )
LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode )
{
BOARD_ITEM* item = const_cast<BOARD_ITEM*>( GetObject( aUcode ) );
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 ) );
aCtx->ReportError( (const char *) msg.c_str() );
return LIBEVAL::VALUE( 0.0 );
// Don't force user to type "A.Type == 'via' && A.Via_Type == 'buried'" when the
// simplier "A.Via_Type == 'buried'" is perfectly clear. Instead, return an undefined
// value when the property doesn't appear on a particular object.
return LIBEVAL::VALUE( "UNDEFINED" );
}
else
{
@ -118,6 +119,7 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx, LIBEVAL::UCOD
else
{
wxString str;
if( !m_isEnum )
{
//printf("item %p Get string '%s'\n", item, (const char*) it->second->Name().c_str() );
@ -125,10 +127,11 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx, LIBEVAL::UCOD
}
else
{
const auto& any = item->Get( it->second );
const wxAny& any = item->Get( it->second );
any.GetAs<wxString>( &str );
//printf("item %p get enum: '%s'\n", item , (const char*) str.c_str() );
}
return LIBEVAL::VALUE( (const char*) str.c_str() );
}
}

View File

@ -85,7 +85,7 @@ public:
m_matchingTypes[type_hash] = prop;
}
virtual LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx, LIBEVAL::UCODE* aUcode ) override;
virtual LIBEVAL::VALUE GetValue( LIBEVAL::UCODE* aUcode ) override;
BOARD_ITEM* GetObject( LIBEVAL::UCODE* aUcode ) const;