Bug fixes for layer expression processing.

1) Push a VAR onto the stack, not a resolved value
2) Don't collapse a PCB_LAYER_VALUE to a VALUE during processing
3) Make sure we run overloaded operators from the correct side

Fixes https://gitlab.com/kicad/code/kicad/issues/12437
This commit is contained in:
Jeff Young 2022-09-16 14:13:34 +01:00
parent d9f75556bd
commit cf1565a16a
6 changed files with 75 additions and 35 deletions

View File

@ -1038,7 +1038,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
reportError( CST_CODEGEN, msg, node->srcPos - (int) node->value.str->length() ); reportError( CST_CODEGEN, msg, node->srcPos - (int) node->value.str->length() );
} }
node->SetUop( TR_UOP_PUSH_VALUE, std::move( vref ) ); node->SetUop( TR_UOP_PUSH_VAR, std::move( vref ) );
node->isTerminal = true; node->isTerminal = true;
break; break;
} }
@ -1090,10 +1090,12 @@ void UOP::Exec( CONTEXT* ctx )
{ {
case TR_UOP_PUSH_VAR: case TR_UOP_PUSH_VAR:
{ {
VALUE* value = ctx->AllocValue(); VALUE* value = nullptr;
if( m_ref ) if( m_ref )
value->Set( m_ref->GetValue( ctx ) ); value = ctx->StoreValue( m_ref->GetValue( ctx ) );
else
value = ctx->AllocValue();
ctx->Push( value ); ctx->Push( value );
} }
@ -1162,10 +1164,20 @@ void UOP::Exec( CONTEXT* ctx )
result = arg1Value > arg2Value ? 1 : 0; result = arg1Value > arg2Value ? 1 : 0;
break; break;
case TR_OP_EQUAL: case TR_OP_EQUAL:
result = arg1 && arg2 && arg1->EqualTo( ctx, arg2 ) ? 1 : 0; if( !arg1 || !arg2 )
result = arg1 == arg2 ? 1 : 0;
else if( arg2->GetType() == VT_UNDEFINED )
result = arg2->EqualTo( ctx, arg1 ) ? 1 : 0;
else
result = arg1->EqualTo( ctx, arg2 ) ? 1 : 0;
break; break;
case TR_OP_NOT_EQUAL: case TR_OP_NOT_EQUAL:
result = arg1 && arg2 && arg1->NotEqualTo( ctx, arg2 ) ? 1 : 0; if( !arg1 || !arg2 )
result = arg1 != arg2 ? 1 : 0;
else if( arg2->GetType() == VT_UNDEFINED )
result = arg2->NotEqualTo( ctx, arg1 ) ? 1 : 0;
else
result = arg1->NotEqualTo( ctx, arg2 ) ? 1 : 0;
break; break;
case TR_OP_BOOL_AND: case TR_OP_BOOL_AND:
result = arg1Value != 0.0 && arg2Value != 0.0 ? 1 : 0; result = arg1Value != 0.0 && arg2Value != 0.0 ? 1 : 0;

View File

@ -296,7 +296,7 @@ public:
virtual ~VAR_REF() {}; virtual ~VAR_REF() {};
virtual VAR_TYPE_T GetType() const = 0; virtual VAR_TYPE_T GetType() const = 0;
virtual VALUE GetValue( CONTEXT* aCtx ) = 0; virtual VALUE* GetValue( CONTEXT* aCtx ) = 0;
}; };
@ -312,7 +312,7 @@ public:
virtual ~CONTEXT() virtual ~CONTEXT()
{ {
for( auto &v : m_ownedValues ) for( VALUE* v : m_ownedValues )
{ {
delete v; delete v;
} }
@ -324,6 +324,12 @@ public:
return m_ownedValues.back(); return m_ownedValues.back();
} }
VALUE* StoreValue( VALUE* aValue )
{
m_ownedValues.emplace_back( aValue );
return m_ownedValues.back();
}
void Push( VALUE* v ) void Push( VALUE* v )
{ {
m_stack[ m_stackPtr++ ] = v; m_stack[ m_stackPtr++ ] = v;

View File

@ -48,6 +48,14 @@
* zone\_connection * zone\_connection
Note: `clearance` and `hole_clearance` rules are not run against items of the same net; `physical_clearance` and `physical_hole_clearance` rules are. Note: `clearance` and `hole_clearance` rules are not run against items of the same net; `physical_clearance` and `physical_hole_clearance` rules are.
<br><br>
### Items
* `A` &nbsp;&nbsp; _the first (or only) item under test_
* `B` &nbsp;&nbsp; _the second item under test (for binary tests)_
* `L` &nbsp;&nbsp; _the layer currently under test_
<br> <br>
### Item Types ### Item Types

View File

@ -49,6 +49,14 @@ _HKI( "### Top-level Clauses\n"
" * zone\\_connection\n" " * zone\\_connection\n"
"\n" "\n"
"Note: `clearance` and `hole_clearance` rules are not run against items of the same net; `physical_clearance` and `physical_hole_clearance` rules are.\n" "Note: `clearance` and `hole_clearance` rules are not run against items of the same net; `physical_clearance` and `physical_hole_clearance` rules are.\n"
"<br><br>\n"
"\n"
"### Items\n"
"\n"
" * `A` &nbsp;&nbsp; _the first (or only) item under test_\n"
" * `B` &nbsp;&nbsp; _the second item under test (for binary tests)_\n"
" * `L` &nbsp;&nbsp; _the layer currently under test_\n"
"\n"
"<br>\n" "<br>\n"
"\n" "\n"
"### Item Types\n" "### Item Types\n"

View File

@ -992,7 +992,8 @@ class PCB_LAYER_VALUE : public LIBEVAL::VALUE
{ {
public: public:
PCB_LAYER_VALUE( PCB_LAYER_ID aLayer ) : PCB_LAYER_VALUE( PCB_LAYER_ID aLayer ) :
LIBEVAL::VALUE( double( aLayer ) ) LIBEVAL::VALUE( LayerName( aLayer ) ),
m_layer( aLayer )
{}; {};
virtual bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override virtual bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
@ -1025,25 +1026,25 @@ public:
mask = i->second; mask = i->second;
} }
PCB_LAYER_ID layerId = ToLAYER_ID( (int) AsDouble() ); return mask.Contains( m_layer );
return mask.Contains( layerId );
} }
protected:
PCB_LAYER_ID m_layer;
}; };
LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx ) LIBEVAL::VALUE* PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
{ {
PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
if( m_itemIndex == 2 ) if( m_itemIndex == 2 )
{ return new PCB_LAYER_VALUE( context->GetLayer() );
PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
return PCB_LAYER_VALUE( context->GetLayer() );
}
BOARD_ITEM* item = GetObject( aCtx ); BOARD_ITEM* item = GetObject( aCtx );
if( !item ) if( !item )
return LIBEVAL::VALUE(); return new LIBEVAL::VALUE();
auto it = m_matchingTypes.find( TYPE_HASH( *item ) ); auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
@ -1053,12 +1054,12 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
// simpler "A.Via_Type == 'buried'" is perfectly clear. Instead, return an undefined // simpler "A.Via_Type == 'buried'" is perfectly clear. Instead, return an undefined
// value when the property doesn't appear on a particular object. // value when the property doesn't appear on a particular object.
return LIBEVAL::VALUE(); return new LIBEVAL::VALUE();
} }
else else
{ {
if( m_type == LIBEVAL::VT_NUMERIC ) if( m_type == LIBEVAL::VT_NUMERIC )
return LIBEVAL::VALUE( (double) item->Get<int>( it->second ) ); return new LIBEVAL::VALUE( (double) item->Get<int>( it->second ) );
else else
{ {
wxString str; wxString str;
@ -1066,7 +1067,7 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
if( !m_isEnum ) if( !m_isEnum )
{ {
str = item->Get<wxString>( it->second ); str = item->Get<wxString>( it->second );
return LIBEVAL::VALUE( str ); return new LIBEVAL::VALUE( str );
} }
else else
{ {
@ -1074,45 +1075,50 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
bool valid = any.GetAs<wxString>( &str ); bool valid = any.GetAs<wxString>( &str );
if( valid ) if( valid )
return LIBEVAL::VALUE( str ); {
if( it->second->Name() == wxT( "Layer" ) )
return new PCB_LAYER_VALUE( context->GetBoard()->GetLayerID( str ) );
else
return new LIBEVAL::VALUE( str );
}
} }
return LIBEVAL::VALUE(); return new LIBEVAL::VALUE();
} }
} }
} }
LIBEVAL::VALUE PCB_EXPR_NETCLASS_REF::GetValue( LIBEVAL::CONTEXT* aCtx ) LIBEVAL::VALUE* PCB_EXPR_NETCLASS_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
{ {
BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( GetObject( aCtx ) ); BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( GetObject( aCtx ) );
if( !item ) if( !item )
return LIBEVAL::VALUE(); return new LIBEVAL::VALUE();
return LIBEVAL::VALUE( item->GetEffectiveNetClass()->GetName() ); return new LIBEVAL::VALUE( item->GetEffectiveNetClass()->GetName() );
} }
LIBEVAL::VALUE PCB_EXPR_NETNAME_REF::GetValue( LIBEVAL::CONTEXT* aCtx ) LIBEVAL::VALUE* PCB_EXPR_NETNAME_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
{ {
BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( GetObject( aCtx ) ); BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( GetObject( aCtx ) );
if( !item ) if( !item )
return LIBEVAL::VALUE(); return new LIBEVAL::VALUE();
return LIBEVAL::VALUE( item->GetNetname() ); return new LIBEVAL::VALUE( item->GetNetname() );
} }
LIBEVAL::VALUE PCB_EXPR_TYPE_REF::GetValue( LIBEVAL::CONTEXT* aCtx ) LIBEVAL::VALUE* PCB_EXPR_TYPE_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
{ {
BOARD_ITEM* item = GetObject( aCtx ); BOARD_ITEM* item = GetObject( aCtx );
if( !item ) if( !item )
return LIBEVAL::VALUE(); return new LIBEVAL::VALUE();
return LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( item->Type() ) ); return new LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( item->Type() ) );
} }

View File

@ -103,7 +103,7 @@ public:
m_matchingTypes[type_hash] = prop; m_matchingTypes[type_hash] = prop;
} }
virtual LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override; LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
BOARD_ITEM* GetObject( const LIBEVAL::CONTEXT* aCtx ) const; BOARD_ITEM* GetObject( const LIBEVAL::CONTEXT* aCtx ) const;
@ -126,7 +126,7 @@ public:
//printf("*** CreateVarRef %p %d\n", this, aItemIndex ); //printf("*** CreateVarRef %p %d\n", this, aItemIndex );
} }
LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override; LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
}; };
@ -141,7 +141,7 @@ public:
//printf("*** CreateVarRef %p %d\n", this, aItemIndex ); //printf("*** CreateVarRef %p %d\n", this, aItemIndex );
} }
LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override; LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
}; };
@ -155,7 +155,7 @@ public:
//printf("*** CreateVarRef %p %d\n", this, aItemIndex ); //printf("*** CreateVarRef %p %d\n", this, aItemIndex );
} }
LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override; LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
}; };