KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbexpr_evaluator.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "pcbexpr_evaluator.h"
21
22#include <inspectable_impl.h>
23
24#include <cstdio>
25#include <memory>
26#include <mutex>
27
28#include <board.h>
29#include <footprint.h>
30#include <lset.h>
32#include <drc/drc_engine.h>
34#include <string_utils.h>
35
36
37/* --------------------------------------------------------------------------------------------
38 * Specialized Expression References
39 */
40
42{
43 wxASSERT( dynamic_cast<const PCBEXPR_CONTEXT*>( aCtx ) );
44
45 const PCBEXPR_CONTEXT* ctx = static_cast<const PCBEXPR_CONTEXT*>( aCtx );
46 BOARD_ITEM* item = ctx->GetItem( m_itemIndex );
47
48 for( PCBEXPR_NAV_STEP step : m_navigation )
49 {
50 if( !item )
51 break;
52
53 switch( step )
54 {
55 // The direct parent, matching the semantics of the "Parent" string property so that
56 // "A.Parent" used as an object refers to the same item as "A.Parent" used as a string.
57 case PCBEXPR_NAV_STEP::PARENT: item = item->GetParent(); break;
58 }
59 }
60
61 return item;
62}
63
64
66{
67public:
69 LIBEVAL::VALUE( LayerName( aLayer ) ),
70 m_layer( aLayer )
71 {};
72
73 virtual bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
74 {
75 // For boards with user-defined layer names there will be 2 entries for each layer
76 // in the ENUM_MAP: one for the canonical layer name and one for the user layer name.
77 // We need to check against both.
78
79 wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices();
80 const wxString& layerName = b->AsString();
81 BOARD* board = static_cast<PCBEXPR_CONTEXT*>( aCtx )->GetBoard();
82
83 {
84 std::shared_lock<std::shared_mutex> readLock( board->m_CachesMutex );
85
86 auto i = board->m_LayerExpressionCache.find( layerName );
87
88 if( i != board->m_LayerExpressionCache.end() )
89 return i->second.Contains( m_layer );
90 }
91
92 LSET mask;
93
94 for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
95 {
96 wxPGChoiceEntry& entry = layerMap[ii];
97
98 if( entry.GetText().Matches( layerName ) )
99 mask.set( ToLAYER_ID( entry.GetValue() ) );
100 }
101
102 {
103 std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
104 board->m_LayerExpressionCache[ layerName ] = mask;
105 }
106
107 return mask.Contains( m_layer );
108 }
109
110protected:
112};
113
114
116{
117public:
118 PCBEXPR_PINTYPE_VALUE( const wxString& aPinTypeName ) :
119 LIBEVAL::VALUE( aPinTypeName )
120 {};
121
122 bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
123 {
124 const wxString& thisStr = AsString();
125 const wxString& otherStr = b->AsString();
126
127 // Case insensitive
128 if( thisStr.IsSameAs( otherStr, false ) )
129 return true;
130
131 // Wildcards
132 if( thisStr.Matches( otherStr ) )
133 return true;
134
135 // Handle cases where the netlist token is different from the EEschema token
136 wxString altStr;
137
138 if( thisStr == wxT( "tri_state" ) )
139 altStr = wxT( "Tri-state" );
140 else if( thisStr == wxT( "power_in" ) )
141 altStr = wxT( "Power input" );
142 else if( thisStr == wxT( "power_out" ) )
143 altStr = wxT( "Power output" );
144 else if( thisStr == wxT( "no_connect" ) )
145 altStr = wxT( "Unconnected" );
146
147 if( !altStr.IsEmpty() )
148 {
149 // Case insensitive
150 if( altStr.IsSameAs( otherStr, false ) )
151 return true;
152
153 // Wildcards
154 if( altStr.Matches( otherStr ) )
155 return true;
156 }
157
158 return false;
159 }
160};
161
162
164{
165public:
167 LIBEVAL::VALUE( wxEmptyString ),
168 m_item( aItem )
169 {};
170
171 const wxString& AsString() const override
172 {
173 const_cast<PCBEXPR_NETCLASS_VALUE*>( this )->Set( m_item->GetEffectiveNetClass()->GetName() );
175 }
176
177 bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
178 {
179 if( const PCBEXPR_NETCLASS_VALUE* bValue = dynamic_cast<const PCBEXPR_NETCLASS_VALUE*>( b ) )
180 return *( m_item->GetEffectiveNetClass() ) == *( bValue->m_item->GetEffectiveNetClass() );
181
182 if( b->GetType() == LIBEVAL::VT_STRING )
183 {
184 // Test constituent net class names. The effective net class name (e.g. CLASS1,CLASS2,OTHER_CLASS) is
185 // tested in the fallthrough condition.
186 for( const NETCLASS* nc : m_item->GetEffectiveNetClass()->GetConstituentNetclasses() )
187 {
188 const wxString& ncName = nc->GetName();
189
190 if( b->StringIsWildcard() )
191 {
192 if( WildCompareString( b->AsString(), ncName, false ) )
193 return true;
194 }
195 else
196 {
197 if( ncName.IsSameAs( b->AsString(), false ) )
198 return true;
199 }
200 }
201 }
202
203 return LIBEVAL::VALUE::EqualTo( aCtx, b );
204 }
205
206 bool NotEqualTo( LIBEVAL::CONTEXT* aCtx, const LIBEVAL::VALUE* b ) const override
207 {
208 if( const PCBEXPR_NETCLASS_VALUE* bValue = dynamic_cast<const PCBEXPR_NETCLASS_VALUE*>( b ) )
209 return *( m_item->GetEffectiveNetClass() ) != *( bValue->m_item->GetEffectiveNetClass() );
210
211 if( b->GetType() == LIBEVAL::VT_STRING )
212 {
213 // Test constituent net class names
214 bool isInConstituents = false;
215
216 for( const NETCLASS* nc : m_item->GetEffectiveNetClass()->GetConstituentNetclasses() )
217 {
218 const wxString& ncName = nc->GetName();
219
220 if( b->StringIsWildcard() )
221 {
222 if( WildCompareString( b->AsString(), ncName, false ) )
223 {
224 isInConstituents = true;
225 break;
226 }
227 }
228 else
229 {
230 if( ncName.IsSameAs( b->AsString(), false ) )
231 {
232 isInConstituents = true;
233 break;
234 }
235 }
236 }
237
238 // Test effective net class name
239 const bool isFullName = LIBEVAL::VALUE::EqualTo( aCtx, b );
240
241 return !isInConstituents && !isFullName;
242 }
243
244 return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
245 }
246
247protected:
249};
250
251
253{
254public:
256 LIBEVAL::VALUE( wxEmptyString ),
257 m_item( dynamic_cast<FOOTPRINT*>( aItem ) )
258 {};
259
260 const wxString& AsString() const override
261 {
262 if( !m_item )
264
265 if( const COMPONENT_CLASS* compClass = m_item->GetComponentClass() )
266 const_cast<PCBEXPR_COMPONENT_CLASS_VALUE*>( this )->Set( compClass->GetName() );
267
269 }
270
271 bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
272 {
273 if( const PCBEXPR_COMPONENT_CLASS_VALUE* bValue = dynamic_cast<const PCBEXPR_COMPONENT_CLASS_VALUE*>( b ) )
274 {
275 if( !m_item || !bValue->m_item )
276 return LIBEVAL::VALUE::EqualTo( aCtx, b );
277
278 const COMPONENT_CLASS* aClass = m_item->GetComponentClass();
279 const COMPONENT_CLASS* bClass = bValue->m_item->GetComponentClass();
280
281 return *aClass == *bClass;
282 }
283
284 if( b->GetType() == LIBEVAL::VT_STRING )
285 {
286 // Test constituent component class names. The effective component class name
287 // (e.g. CLASS1,CLASS2,OTHER_CLASS) is tested in the fallthrough condition.
288 for( const COMPONENT_CLASS* cc : m_item->GetComponentClass()->GetConstituentClasses() )
289 {
290 const wxString& ccName = cc->GetName();
291
292 if( b->StringIsWildcard() )
293 {
294 if( WildCompareString( b->AsString(), ccName, false ) )
295 return true;
296 }
297 else
298 {
299 if( ccName.IsSameAs( b->AsString(), false ) )
300 return true;
301 }
302 }
303 }
304
305 return LIBEVAL::VALUE::EqualTo( aCtx, b );
306 }
307
308 bool NotEqualTo( LIBEVAL::CONTEXT* aCtx, const LIBEVAL::VALUE* b ) const override
309 {
310 if( const PCBEXPR_COMPONENT_CLASS_VALUE* bValue = dynamic_cast<const PCBEXPR_COMPONENT_CLASS_VALUE*>( b ) )
311 {
312 if( !m_item || !bValue->m_item )
313 return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
314
315 const COMPONENT_CLASS* aClass = m_item->GetComponentClass();
316 const COMPONENT_CLASS* bClass = bValue->m_item->GetComponentClass();
317
318 return *aClass != *bClass;
319 }
320
321 if( b->GetType() == LIBEVAL::VT_STRING )
322 {
323 // Test constituent component class names
324 bool isInConstituents = false;
325
326 for( const COMPONENT_CLASS* cc : m_item->GetComponentClass()->GetConstituentClasses() )
327 {
328 const wxString& ccName = cc->GetName();
329
330 if( b->StringIsWildcard() )
331 {
332 if( WildCompareString( b->AsString(), ccName, false ) )
333 {
334 isInConstituents = true;
335 break;
336 }
337 }
338 else
339 {
340 if( ccName.IsSameAs( b->AsString(), false ) )
341 {
342 isInConstituents = true;
343 break;
344 }
345 }
346 }
347
348 // Test effective component class name
349 const bool isFullName = LIBEVAL::VALUE::EqualTo( aCtx, b );
350
351 return !isInConstituents && !isFullName;
352 }
353
354 return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
355 }
356
357protected:
359};
360
361
363{
364public:
366 LIBEVAL::VALUE( wxEmptyString ),
367 m_item( aItem )
368 {};
369
370 const wxString& AsString() const override
371 {
372 const_cast<PCBEXPR_NET_VALUE*>( this )->Set( m_item->GetNetname() );
374 }
375
376 bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
377 {
378 if( const PCBEXPR_NET_VALUE* bValue = dynamic_cast<const PCBEXPR_NET_VALUE*>( b ) )
379 return m_item->GetNetCode() == bValue->m_item->GetNetCode();
380 else
381 return LIBEVAL::VALUE::EqualTo( aCtx, b );
382 }
383
384 bool NotEqualTo( LIBEVAL::CONTEXT* aCtx, const LIBEVAL::VALUE* b ) const override
385 {
386 if( const PCBEXPR_NET_VALUE* bValue = dynamic_cast<const PCBEXPR_NET_VALUE*>( b ) )
387 return m_item->GetNetCode() != bValue->m_item->GetNetCode();
388 else
389 return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
390 }
391
392protected:
394};
395
396
398{
399 auto it = m_typeOverrides.find( aItem );
400 return it != m_typeOverrides.end() ? it->second : aItem->Type();
401}
402
403
405{
406 PCBEXPR_CONTEXT* context = static_cast<PCBEXPR_CONTEXT*>( aCtx );
407
408 if( m_type == LIBEVAL::VT_NULL )
410
411 if( m_itemIndex == 2 )
412 return new PCBEXPR_LAYER_VALUE( context->GetLayer() );
413
414 BOARD_ITEM* item = GetObject( aCtx );
415
416 if( !item )
417 return new LIBEVAL::VALUE();
418
419 auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
420
421 if( it == m_matchingTypes.end() )
422 {
423 // If the property isn't defined on the item itself but is defined on its parent
424 // footprint (e.g. Reference, Value), resolve against the parent so that conditions
425 // like "A.Reference == 'J1'" match pads and graphics belonging to J1.
426 if( FOOTPRINT* parentFp = item->GetParentFootprint() )
427 {
428 auto parentIt = m_matchingTypes.find( TYPE_HASH( *parentFp ) );
429
430 if( parentIt != m_matchingTypes.end() )
431 {
432 item = parentFp;
433 it = parentIt;
434 }
435 }
436 }
437
438 if( it == m_matchingTypes.end() )
439 {
440 // Don't force user to type "A.Type == 'via' && A.Via_Type == 'buried'" when the
441 // simpler "A.Via_Type == 'buried'" is perfectly clear. Instead, return an undefined
442 // value when the property doesn't appear on a particular object.
443
444 return new LIBEVAL::VALUE();
445 }
446 else
447 {
449 {
450 if( m_isOptional )
451 {
452 std::optional<int> val = item->Get<std::optional<int>>( it->second );
453
454 if( val.has_value() )
455 return new LIBEVAL::VALUE( static_cast<double>( val.value() ) );
456
458 }
459
460 return new LIBEVAL::VALUE( static_cast<double>( item->Get<int>( it->second ) ) );
461 }
463 {
464 if( m_isOptional )
465 {
466 std::optional<double> val = item->Get<std::optional<double>>( it->second );
467
468 if( val.has_value() )
469 return new LIBEVAL::VALUE( val.value() );
470
472 }
473
474 return new LIBEVAL::VALUE( item->Get<double>( it->second ) );
475 }
476 else
477 {
478 wxString str;
479
480 if( !m_isEnum )
481 {
482 str = item->Get<wxString>( it->second );
483
484 if( it->second->Name() == wxT( "Pin Type" ) )
485 return new PCBEXPR_PINTYPE_VALUE( str );
486
487 // If it quacks like a duck, it is a duck
488 double doubleVal;
489
491 return new LIBEVAL::VALUE( doubleVal );
492
493 return new LIBEVAL::VALUE( str );
494 }
495 else if( it->second->Name() == wxT( "Layer" )
496 || it->second->Name() == wxT( "Layer Top" )
497 || it->second->Name() == wxT( "Layer Bottom" ) )
498 {
499 const wxAny& any = item->Get( it->second );
500 PCB_LAYER_ID layer;
501
502 if( any.GetAs<PCB_LAYER_ID>( &layer ) )
503 return new PCBEXPR_LAYER_VALUE( layer );
504 else if( any.GetAs<wxString>( &str ) )
505 return new PCBEXPR_LAYER_VALUE( context->GetBoard()->GetLayerID( str ) );
506 }
507 else
508 {
509 const wxAny& any = item->Get( it->second );
510
511 if( any.GetAs<wxString>( &str ) )
512 return new LIBEVAL::VALUE( str );
513 }
514
515 return new LIBEVAL::VALUE();
516 }
517 }
518}
519
520
522{
523 BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( GetObject( aCtx ) );
524
525 if( !item )
526 return new LIBEVAL::VALUE();
527
528 return new PCBEXPR_NETCLASS_VALUE( item );
529}
530
531
533{
534 BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( GetObject( aCtx ) );
535
536 if( !item )
537 return new LIBEVAL::VALUE();
538
539 // Resolve component class via the parent footprint so that conditions like
540 // "A.ComponentClass == 'X'" match pads and graphics inside the footprint.
541 if( item->Type() != PCB_FOOTPRINT_T )
542 item = item->GetParentFootprint();
543
544 if( !item )
545 return new LIBEVAL::VALUE();
546
547 return new PCBEXPR_COMPONENT_CLASS_VALUE( item );
548}
549
550
552{
553 BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( GetObject( aCtx ) );
554
555 if( !item )
556 return new LIBEVAL::VALUE();
557
558 return new PCBEXPR_NET_VALUE( item );
559}
560
561
563{
564 BOARD_ITEM* item = GetObject( aCtx );
565
566 if( !item )
567 return new LIBEVAL::VALUE();
568
569 PCBEXPR_CONTEXT* ctx = static_cast<PCBEXPR_CONTEXT*>( aCtx );
570 KICAD_T type = ctx->GetEffectiveType( item );
571
572 return new LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( type ) );
573}
574
575
577{
578 wxString nameLower = aName.Lower();
579
581
582 if( registry.IsGeometryDependent( nameLower ) )
584
585 return registry.Get( nameLower );
586}
587
588
589std::unique_ptr<LIBEVAL::VAR_REF> PCBEXPR_UCODE::CreateVarRef( const wxString& aVar,
590 const wxString& aField )
591{
593 std::unique_ptr<PCBEXPR_VAR_REF> vref;
594
595 if( aVar.IsSameAs( wxT( "null" ), false ) )
596 {
597 vref = std::make_unique<PCBEXPR_VAR_REF>( 0 );
598 vref->SetType( LIBEVAL::VT_NULL );
599 return vref;
600 }
601
602 // The receiver may be a navigation chain such as "A.Parent". Split off the base variable
603 // and translate each remaining segment into a navigation step. Only "Parent" is supported.
604
605 wxString baseVar = aVar;
606 std::vector<PCBEXPR_NAV_STEP> navigation;
607
608 if( aVar.Contains( wxT( "." ) ) )
609 {
610 wxArrayString tokens = wxSplit( aVar, '.' );
611 baseVar = tokens.IsEmpty() ? wxString() : tokens[0];
612
613 for( size_t i = 1; i < tokens.GetCount(); ++i )
614 {
615 if( tokens[i].CmpNoCase( wxT( "Parent" ) ) == 0 )
616 navigation.push_back( PCBEXPR_NAV_STEP::PARENT );
617 else
618 return nullptr;
619 }
620
621 // Navigation is only meaningful for the item operands; the layer pseudo-item "L" has
622 // no parent.
623 if( baseVar != wxT( "A" ) && baseVar != wxT( "AB" ) && baseVar != wxT( "B" ) )
624 return nullptr;
625 }
626
627 auto withNav =
628 [&navigation]( std::unique_ptr<PCBEXPR_VAR_REF> aRef ) -> std::unique_ptr<PCBEXPR_VAR_REF>
629 {
630 if( aRef && !navigation.empty() )
631 aRef->SetNavigation( navigation );
632
633 return aRef;
634 };
635
636 // Check for a couple of very common cases and compile them straight to "object code".
637
638 if( aField.CmpNoCase( wxT( "NetClass" ) ) == 0 )
639 {
640 if( baseVar == wxT( "A" ) )
641 return withNav( std::make_unique<PCBEXPR_NETCLASS_REF>( 0 ) );
642 else if( baseVar == wxT( "B" ) )
643 return withNav( std::make_unique<PCBEXPR_NETCLASS_REF>( 1 ) );
644 else
645 return nullptr;
646 }
647 else if( aField.CmpNoCase( wxT( "ComponentClass" ) ) == 0 )
648 {
649 if( baseVar == wxT( "A" ) )
650 return withNav( std::make_unique<PCBEXPR_COMPONENT_CLASS_REF>( 0 ) );
651 else if( baseVar == wxT( "B" ) )
652 return withNav( std::make_unique<PCBEXPR_COMPONENT_CLASS_REF>( 1 ) );
653 else
654 return nullptr;
655 }
656 else if( aField.CmpNoCase( wxT( "NetName" ) ) == 0 )
657 {
658 if( baseVar == wxT( "A" ) )
659 return withNav( std::make_unique<PCBEXPR_NETNAME_REF>( 0 ) );
660 else if( baseVar == wxT( "B" ) )
661 return withNav( std::make_unique<PCBEXPR_NETNAME_REF>( 1 ) );
662 else
663 return nullptr;
664 }
665 else if( aField.CmpNoCase( wxT( "Type" ) ) == 0 )
666 {
667 if( baseVar == wxT( "A" ) )
668 return withNav( std::make_unique<PCBEXPR_TYPE_REF>( 0 ) );
669 else if( baseVar == wxT( "B" ) )
670 return withNav( std::make_unique<PCBEXPR_TYPE_REF>( 1 ) );
671 else
672 return nullptr;
673 }
674
675 if( baseVar == wxT( "A" ) || baseVar == wxT( "AB" ) )
676 vref = std::make_unique<PCBEXPR_VAR_REF>( 0 );
677 else if( baseVar == wxT( "B" ) )
678 vref = std::make_unique<PCBEXPR_VAR_REF>( 1 );
679 else if( baseVar == wxT( "L" ) )
680 vref = std::make_unique<PCBEXPR_VAR_REF>( 2 );
681 else
682 return nullptr;
683
684 vref->SetNavigation( navigation );
685
686 if( aField.length() == 0 ) // return reference to base object
687 return vref;
688
689 wxString field( aField );
690 field.Replace( wxT( "_" ), wxT( " " ) );
691
692 for( const PROPERTY_MANAGER::CLASS_INFO& cls : propMgr.GetAllClasses() )
693 {
694 if( propMgr.IsOfType( cls.type, TYPE_HASH( BOARD_ITEM ) ) )
695 {
696 PROPERTY_BASE* prop = propMgr.GetProperty( cls.type, field );
697
698 if( prop )
699 {
700 vref->AddAllowedClass( cls.type, prop );
701
702 if( prop->TypeHash() == TYPE_HASH( int ) )
703 {
704 vref->SetType( LIBEVAL::VT_NUMERIC );
705 }
706 else if( prop->TypeHash() == TYPE_HASH( std::optional<int> ) )
707 {
708 vref->SetType( LIBEVAL::VT_NUMERIC );
709 vref->SetIsOptional();
710 }
711 else if( prop->TypeHash() == TYPE_HASH( double ) )
712 {
713 vref->SetType( LIBEVAL::VT_NUMERIC_DOUBLE );
714 }
715 else if( prop->TypeHash() == TYPE_HASH( std::optional<double> ) )
716 {
717 vref->SetType( LIBEVAL::VT_NUMERIC_DOUBLE );
718 vref->SetIsOptional();
719 }
720 else if( prop->TypeHash() == TYPE_HASH( bool ) )
721 {
722 vref->SetType( LIBEVAL::VT_NUMERIC );
723 }
724 else if( prop->TypeHash() == TYPE_HASH( wxString ) )
725 {
726 vref->SetType( LIBEVAL::VT_STRING );
727 }
728 else if ( prop->HasChoices() )
729 { // it's an enum, we treat it as string
730 vref->SetType( LIBEVAL::VT_STRING );
731 vref->SetIsEnum( true );
732 }
733 else
734 {
735 wxString msg = wxString::Format( wxT( "PCBEXPR_UCODE::createVarRef: Unknown "
736 "property type %s from %s." ),
737 cls.name,
738 field );
739 wxFAIL_MSG( msg );
740 }
741 }
742 }
743 }
744
745 if( vref->GetType() == LIBEVAL::VT_UNDEFINED )
746 vref->SetType( LIBEVAL::VT_PARSE_ERROR );
747
748 return vref;
749}
750
751
753{
754 if( m_items[0] )
755 return m_items[0]->GetBoard();
756
757 return nullptr;
758}
759
760
761/* --------------------------------------------------------------------------------------------
762 * Unit Resolvers
763 */
764
765const std::vector<wxString>& PCBEXPR_UNIT_RESOLVER::GetSupportedUnits() const
766{
767 static const std::vector<wxString> pcbUnits = { wxT( "mil" ), wxT( "mm" ), wxT( "in" ),
768 wxT( "deg" ), wxT( "fs" ), wxT( "ps" ) };
769
770
771 return pcbUnits;
772}
773
774
776{
777 return _( "must be mm, in, mil, deg, fs, or ps" );
778}
779
780
781const std::vector<EDA_UNITS>& PCBEXPR_UNIT_RESOLVER::GetSupportedUnitsTypes() const
782{
783 static const std::vector<EDA_UNITS> pcbUnits = { EDA_UNITS::MILS, EDA_UNITS::MM, EDA_UNITS::INCH,
785
786 return pcbUnits;
787}
788
789
790double PCBEXPR_UNIT_RESOLVER::Convert( const wxString& aString, int unitId ) const
791{
792 double v = wxAtof( aString );
793
794 switch( unitId )
795 {
799 case 3: return v;
802 default: return v;
803 }
804};
805
806
807const std::vector<wxString>& PCBEXPR_UNITLESS_RESOLVER::GetSupportedUnits() const
808{
809 static const std::vector<wxString> emptyUnits;
810
811 return emptyUnits;
812}
813
814
815const std::vector<EDA_UNITS>& PCBEXPR_UNITLESS_RESOLVER::GetSupportedUnitsTypes() const
816{
817 static const std::vector<EDA_UNITS> emptyUnits;
818
819 return emptyUnits;
820}
821
822
823double PCBEXPR_UNITLESS_RESOLVER::Convert( const wxString& aString, int unitId ) const
824{
825 return wxAtof( aString );
826};
827
828
830{
831 m_unitResolver.reset( aUnitResolver );
832}
833
834
835/* --------------------------------------------------------------------------------------------
836 * PCB Expression Evaluator
837 */
838
840 m_result( 0 ),
841 m_units( EDA_UNITS::MM ),
842 m_compiler( aUnitResolver ),
843 m_ucode(),
845{
846}
847
848
852
853
854bool PCBEXPR_EVALUATOR::Evaluate( const wxString& aExpr )
855{
856 PCBEXPR_UCODE ucode;
857 PCBEXPR_CONTEXT preflightContext( NULL_CONSTRAINT, F_Cu );
858
859 if( !m_compiler.Compile( aExpr.ToUTF8().data(), &ucode, &preflightContext ) )
860 return false;
861
862 PCBEXPR_CONTEXT evaluationContext( NULL_CONSTRAINT, F_Cu );
863 LIBEVAL::VALUE* result = ucode.Run( &evaluationContext );
864
865 if( result->GetType() == LIBEVAL::VT_NUMERIC )
866 {
867 m_result = KiROUND( result->AsDouble() );
868 m_units = result->GetUnits();
869 }
870
871 return true;
872}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
BASE_SET & set(size_t pos)
Definition base_set.h:116
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
FOOTPRINT * GetParentFootprint() const
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:231
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
PCB_LAYER_ID GetLayerID(const wxString &aLayerName) const
Return the ID of a layer.
Definition board.cpp:773
std::unordered_map< wxString, LSET > m_LayerExpressionCache
Definition board.h:1674
std::shared_mutex m_CachesMutex
Definition board.h:1660
A lightweight representation of a component class.
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
static ENUM_MAP< T > & Instance()
Definition property.h:721
wxAny Get(PROPERTY_BASE *aProperty) const
std::unique_ptr< UNIT_RESOLVER > m_unitResolver
VALUE * Run(CONTEXT *ctx)
void Set(double aValue)
virtual const wxString & AsString() const
bool StringIsWildcard() const
static VALUE * MakeNullValue()
virtual bool NotEqualTo(CONTEXT *aCtx, const VALUE *b) const
VAR_TYPE_T GetType() const
virtual bool EqualTo(CONTEXT *aCtx, const VALUE *b) const
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:38
bool IsGeometryDependent(const wxString &name) const
LIBEVAL::FUNC_CALL_REF Get(const wxString &name)
static PCBEXPR_BUILTIN_FUNCTIONS & Instance()
PCBEXPR_COMPILER(LIBEVAL::UNIT_RESOLVER *aUnitResolver)
LIBEVAL::VALUE * GetValue(LIBEVAL::CONTEXT *aCtx) override
bool NotEqualTo(LIBEVAL::CONTEXT *aCtx, const LIBEVAL::VALUE *b) const override
const wxString & AsString() const override
PCBEXPR_COMPONENT_CLASS_VALUE(BOARD_ITEM *aItem)
bool EqualTo(LIBEVAL::CONTEXT *aCtx, const VALUE *b) const override
BOARD_ITEM * m_items[2]
BOARD * GetBoard() const
KICAD_T GetEffectiveType(const BOARD_ITEM *aItem) const
PCB_LAYER_ID GetLayer() const
std::map< const BOARD_ITEM *, KICAD_T > m_typeOverrides
BOARD_ITEM * GetItem(int index) const
LIBEVAL::ERROR_STATUS m_errorStatus
PCBEXPR_EVALUATOR(LIBEVAL::UNIT_RESOLVER *aUnitResolver)
PCBEXPR_COMPILER m_compiler
bool Evaluate(const wxString &aExpr)
PCBEXPR_LAYER_VALUE(PCB_LAYER_ID aLayer)
virtual bool EqualTo(LIBEVAL::CONTEXT *aCtx, const VALUE *b) const override
LIBEVAL::VALUE * GetValue(LIBEVAL::CONTEXT *aCtx) override
bool EqualTo(LIBEVAL::CONTEXT *aCtx, const VALUE *b) const override
BOARD_CONNECTED_ITEM * m_item
PCBEXPR_NETCLASS_VALUE(BOARD_CONNECTED_ITEM *aItem)
const wxString & AsString() const override
bool NotEqualTo(LIBEVAL::CONTEXT *aCtx, const LIBEVAL::VALUE *b) const override
LIBEVAL::VALUE * GetValue(LIBEVAL::CONTEXT *aCtx) override
bool EqualTo(LIBEVAL::CONTEXT *aCtx, const VALUE *b) const override
BOARD_CONNECTED_ITEM * m_item
PCBEXPR_NET_VALUE(BOARD_CONNECTED_ITEM *aItem)
bool NotEqualTo(LIBEVAL::CONTEXT *aCtx, const LIBEVAL::VALUE *b) const override
const wxString & AsString() const override
bool EqualTo(LIBEVAL::CONTEXT *aCtx, const VALUE *b) const override
PCBEXPR_PINTYPE_VALUE(const wxString &aPinTypeName)
LIBEVAL::VALUE * GetValue(LIBEVAL::CONTEXT *aCtx) override
virtual std::unique_ptr< LIBEVAL::VAR_REF > CreateVarRef(const wxString &aVar, const wxString &aField) override
virtual LIBEVAL::FUNC_CALL_REF CreateFuncCall(const wxString &aName) override
bool m_hasGeometryDependentFunctions
const std::vector< wxString > & GetSupportedUnits() const override
const std::vector< EDA_UNITS > & GetSupportedUnitsTypes() const override
double Convert(const wxString &aString, int unitId) const override
double Convert(const wxString &aString, int unitId) const override
const std::vector< EDA_UNITS > & GetSupportedUnitsTypes() const override
wxString GetSupportedUnitsMessage() const override
const std::vector< wxString > & GetSupportedUnits() const override
std::vector< PCBEXPR_NAV_STEP > m_navigation
std::unordered_map< TYPE_ID, PROPERTY_BASE * > m_matchingTypes
LIBEVAL::VALUE * GetValue(LIBEVAL::CONTEXT *aCtx) override
LIBEVAL::VAR_TYPE_T m_type
BOARD_ITEM * GetObject(const LIBEVAL::CONTEXT *aCtx) const
virtual size_t TypeHash() const =0
Return type-id of the property type.
virtual bool HasChoices() const
Return true if this PROPERTY has a limited set of possible values.
Definition property.h:246
Provide class metadata.Helper macro to map type hashes to names.
CLASSES_INFO GetAllClasses()
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE * GetProperty(TYPE_ID aType, const wxString &aProperty) const
Return a property for a specific type.
bool IsOfType(TYPE_ID aDerived, TYPE_ID aBase) const
Return true if aDerived is inherited from aBase.
A type-safe container of any type.
Definition ki_any.h:92
@ NULL_CONSTRAINT
Definition drc_rule.h:50
#define _(s)
EDA_UNITS
Definition eda_units.h:44
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
Definition layer_id.cpp:31
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ F_Cu
Definition layer_ids.h:60
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
KICOMMON_API double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue to a double.
std::function< void(CONTEXT *, void *)> FUNC_CALL_REF
PCBEXPR_NAV_STEP
#define TYPE_HASH(x)
Definition property.h:74
bool WildCompareString(const wxString &pattern, const wxString &string_to_tst, bool case_sensitive)
Compare a string against wild card (* and ?) pattern using the usual rules.
static const long long MM
wxString result
Test unit parsing edge cases and error handling.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:71
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:79