From ecdc7ee08f733a0ece688abbae8bfbe1b0c44041 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Mon, 2 Dec 2024 16:29:41 -0500 Subject: [PATCH] Add a null type for libeval / std::optional support Fixes https://gitlab.com/kicad/code/kicad/-/issues/19158 --- common/libeval_compiler/libeval_compiler.cpp | 3 ++ include/libeval_compiler/libeval_compiler.h | 10 ++++++- .../panel_setup_rules_help_9more_examples.h | 2 +- .../panel_setup_rules_help_9more_examples.md | 2 +- pcbnew/pcbexpr_evaluator.cpp | 29 +++++++++++++++++-- pcbnew/pcbexpr_evaluator.h | 7 ++++- 6 files changed, 47 insertions(+), 6 deletions(-) diff --git a/common/libeval_compiler/libeval_compiler.cpp b/common/libeval_compiler/libeval_compiler.cpp index 090b4d0a06..70fa9ff8d5 100644 --- a/common/libeval_compiler/libeval_compiler.cpp +++ b/common/libeval_compiler/libeval_compiler.cpp @@ -115,6 +115,9 @@ bool VALUE::EqualTo( CONTEXT* aCtx, const VALUE* b ) const if( m_type == VT_UNDEFINED || b->m_type == VT_UNDEFINED ) return false; + if( m_type == VT_NULL && b->m_type == VT_NULL ) + return true; + if( m_type == VT_NUMERIC && b->m_type == VT_NUMERIC ) { return AsDouble() == b->AsDouble(); diff --git a/include/libeval_compiler/libeval_compiler.h b/include/libeval_compiler/libeval_compiler.h index d9e24b82fe..4ec26378a5 100644 --- a/include/libeval_compiler/libeval_compiler.h +++ b/include/libeval_compiler/libeval_compiler.h @@ -85,7 +85,8 @@ enum VAR_TYPE_T VT_STRING = 1, VT_NUMERIC, VT_UNDEFINED, - VT_PARSE_ERROR + VT_PARSE_ERROR, + VT_NULL }; enum TOKEN_TYPE_T @@ -210,6 +211,13 @@ public: m_isDeferredStr( false ) {}; + static VALUE* MakeNullValue() + { + VALUE* v = new VALUE(); + v->m_type = VT_NULL; + return v; + } + virtual ~VALUE() {}; diff --git a/pcbnew/dialogs/panel_setup_rules_help_9more_examples.h b/pcbnew/dialogs/panel_setup_rules_help_9more_examples.h index 6373a174be..5f07de59b2 100644 --- a/pcbnew/dialogs/panel_setup_rules_help_9more_examples.h +++ b/pcbnew/dialogs/panel_setup_rules_help_9more_examples.h @@ -94,7 +94,7 @@ _HKI( "### More Examples\n" "\n" " # Disallow solder mask margin overrides\n" " (rule \"disallow solder mask margin overrides\"\n" -" (constraint assertion \"A.Soldermask_Margin_Override == 0mm\")\n" +" (constraint assertion \"A.Soldermask_Margin_Override == null\")\n" " (condition \"A.Type == 'Pad'\"))\n" "\n" "\n" diff --git a/pcbnew/dialogs/panel_setup_rules_help_9more_examples.md b/pcbnew/dialogs/panel_setup_rules_help_9more_examples.md index d5c66931ef..26421ff017 100644 --- a/pcbnew/dialogs/panel_setup_rules_help_9more_examples.md +++ b/pcbnew/dialogs/panel_setup_rules_help_9more_examples.md @@ -93,7 +93,7 @@ # Disallow solder mask margin overrides (rule "disallow solder mask margin overrides" - (constraint assertion "A.Soldermask_Margin_Override == 0mm") + (constraint assertion "A.Soldermask_Margin_Override == null") (condition "A.Type == 'Pad'")) diff --git a/pcbnew/pcbexpr_evaluator.cpp b/pcbnew/pcbexpr_evaluator.cpp index 652c7c03f9..73f480ddb4 100644 --- a/pcbnew/pcbexpr_evaluator.cpp +++ b/pcbnew/pcbexpr_evaluator.cpp @@ -272,6 +272,9 @@ LIBEVAL::VALUE* PCBEXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx ) { PCBEXPR_CONTEXT* context = static_cast( aCtx ); + if( m_type == LIBEVAL::VT_NULL ) + return LIBEVAL::VALUE::MakeNullValue(); + if( m_itemIndex == 2 ) return new PCBEXPR_LAYER_VALUE( context->GetLayer() ); @@ -294,7 +297,17 @@ LIBEVAL::VALUE* PCBEXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx ) { if( m_type == LIBEVAL::VT_NUMERIC ) { - return new LIBEVAL::VALUE( (double) item->Get( it->second ) ); + if( m_isOptional ) + { + auto val = item->Get>( it->second ); + + if( val.has_value() ) + return new LIBEVAL::VALUE( static_cast( val.value() ) ); + + return LIBEVAL::VALUE::MakeNullValue(); + } + + return new LIBEVAL::VALUE( static_cast( item->Get( it->second ) ) ); } else { @@ -394,6 +407,13 @@ std::unique_ptr PCBEXPR_UCODE::CreateVarRef( const wxString& a PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); std::unique_ptr vref; + if( aVar.IsSameAs( wxT( "null" ), false ) ) + { + vref = std::make_unique( 0 ); + vref->SetType( LIBEVAL::VT_NULL ); + return vref; + } + // Check for a couple of very common cases and compile them straight to "object code". if( aField.CmpNoCase( wxT( "NetClass" ) ) == 0 ) @@ -464,6 +484,11 @@ std::unique_ptr PCBEXPR_UCODE::CreateVarRef( const wxString& a { vref->SetType( LIBEVAL::VT_NUMERIC ); } + if( prop->TypeHash() == TYPE_HASH( std::optional ) ) + { + vref->SetType( LIBEVAL::VT_NUMERIC ); + vref->SetIsOptional(); + } else if( prop->TypeHash() == TYPE_HASH( bool ) ) { vref->SetType( LIBEVAL::VT_NUMERIC ); @@ -475,7 +500,7 @@ std::unique_ptr PCBEXPR_UCODE::CreateVarRef( const wxString& a else if ( prop->HasChoices() ) { // it's an enum, we treat it as string vref->SetType( LIBEVAL::VT_STRING ); - vref->SetIsEnum ( true ); + vref->SetIsEnum( true ); } else { diff --git a/pcbnew/pcbexpr_evaluator.h b/pcbnew/pcbexpr_evaluator.h index 6541cf8d56..4f369c37cd 100644 --- a/pcbnew/pcbexpr_evaluator.h +++ b/pcbnew/pcbexpr_evaluator.h @@ -85,7 +85,8 @@ public: PCBEXPR_VAR_REF( int aItemIndex ) : m_itemIndex( aItemIndex ), m_type( LIBEVAL::VT_UNDEFINED ), - m_isEnum( false ) + m_isEnum( false ), + m_isOptional( false ) {} ~PCBEXPR_VAR_REF() {}; @@ -93,6 +94,9 @@ public: void SetIsEnum( bool s ) { m_isEnum = s; } bool IsEnum() const { return m_isEnum; } + void SetIsOptional( bool s = true ) { m_isOptional = s; } + bool IsOptional() const { return m_isOptional; } + void SetType( LIBEVAL::VAR_TYPE_T type ) { m_type = type; } LIBEVAL::VAR_TYPE_T GetType() const override { return m_type; } @@ -110,6 +114,7 @@ private: int m_itemIndex; LIBEVAL::VAR_TYPE_T m_type; bool m_isEnum; + bool m_isOptional; };