KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_rule_condition.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
21#include <board_item.h>
22#include <reporter.h>
24#include <pcbexpr_evaluator.h>
25#include <zone.h>
26
27DRC_RULE_CONDITION::DRC_RULE_CONDITION( const wxString& aExpression ) :
28 m_expression( aExpression ),
29 m_ucode ( nullptr )
30{
31}
32
33
37
38
39bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB,
40 int aConstraint, PCB_LAYER_ID aLayer, REPORTER* aReporter )
41{
42 if( GetExpression().IsEmpty() )
43 return true;
44
45 if( !m_ucode )
46 {
47 if( aReporter )
48 aReporter->Report( _( "ERROR in expression." ) );
49
50 return false;
51 }
52
53 // The no-reporter path is the DRC hot path, so reuse a per-thread context rather than
54 // constructing and tearing one down for each of the millions of condition evaluations. The
55 // reporter path is rare and keeps a throwaway context so its error-callback captures stay
56 // self-contained. A re-entrant evaluation on the same thread (should a predicate ever
57 // evaluate a rule itself) must not reset the outer evaluation's in-flight context, so only the
58 // outermost call reuses the per-thread context; a nested one falls back to a throwaway.
59 thread_local PCBEXPR_CONTEXT tlsCtx;
60 thread_local bool tlsCtxBusy = false;
61
62 struct TLS_RELEASE
63 {
64 bool* busy = nullptr;
65 ~TLS_RELEASE() { if( busy ) *busy = false; }
66 } tlsRelease;
67
68 std::unique_ptr<PCBEXPR_CONTEXT> ownedCtx;
69 PCBEXPR_CONTEXT* ctx;
70
71 if( aReporter || tlsCtxBusy )
72 {
73 ownedCtx = std::make_unique<PCBEXPR_CONTEXT>( aConstraint, aLayer );
74 ctx = ownedCtx.get();
75
76 if( aReporter )
77 {
79 [&]( const wxString& aMessage, int aOffset )
80 {
81 aReporter->Report( _( "ERROR:" ) + wxS( " " ) + aMessage );
82 } );
83 }
84 }
85 else
86 {
87 tlsCtxBusy = true;
88 tlsRelease.busy = &tlsCtxBusy;
89 tlsCtx.Reset();
90 tlsCtx.SetConstraint( aConstraint );
91 tlsCtx.SetLayer( aLayer );
92 ctx = &tlsCtx;
93 }
94
95 BOARD_ITEM* a = const_cast<BOARD_ITEM*>( aItemA );
96 BOARD_ITEM* b = const_cast<BOARD_ITEM*>( aItemB );
97
98 // Treat teardrop areas as tracks for DRC rule matching
99 if( a && a->Type() == PCB_ZONE_T && static_cast<ZONE*>( a )->IsTeardropArea() )
100 ctx->SetTypeOverride( a, PCB_TRACE_T );
101
102 if( b && b->Type() == PCB_ZONE_T && static_cast<ZONE*>( b )->IsTeardropArea() )
103 ctx->SetTypeOverride( b, PCB_TRACE_T );
104
105 ctx->SetItems( a, b );
106
107 if( m_ucode->Run( ctx )->AsDouble() != 0.0 )
108 {
109 return true;
110 }
111 else if( aItemB ) // Conditions are commutative
112 {
113 ctx->SetItems( b, a );
114
115 if( m_ucode->Run( ctx )->AsDouble() != 0.0 )
116 return true;
117 }
118
119 return false;
120}
121
122
123bool DRC_RULE_CONDITION::Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset )
124{
125 PCBEXPR_COMPILER compiler( new PCBEXPR_UNIT_RESOLVER() );
126
127 if( aReporter )
128 {
129 compiler.SetErrorCallback(
130 [&]( const wxString& aMessage, int aOffset )
131 {
132 wxString rest;
133 wxString first = aMessage.BeforeFirst( '|', &rest );
134 wxString msg = wxString::Format( _( "ERROR: <a href='%d:%d'>%s</a>%s" ),
135 aSourceLine,
136 aSourceOffset + aOffset,
137 first,
138 rest );
139
140 aReporter->Report( msg, RPT_SEVERITY_ERROR );
141 } );
142 }
143
144 m_ucode = std::make_unique<PCBEXPR_UCODE>();
145
146 PCBEXPR_CONTEXT preflightContext( 0, F_Cu );
147
148 bool ok = compiler.Compile( GetExpression().ToUTF8().data(), m_ucode.get(), &preflightContext );
149 return ok;
150}
151
152
154{
155 return m_ucode && m_ucode->HasGeometryDependentFunctions();
156}
157
158
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
std::unique_ptr< PCBEXPR_UCODE > m_ucode
DRC_RULE_CONDITION(const wxString &aExpression="")
bool Compile(REPORTER *aReporter, int aSourceLine=0, int aSourceOffset=0)
bool HasGeometryDependentFunctions() const
wxString GetExpression() const
bool EvaluateFor(const BOARD_ITEM *aItemA, const BOARD_ITEM *aItemB, int aConstraint, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
bool Compile(const wxString &aString, UCODE *aCode, CONTEXT *aPreflightContext)
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
void SetConstraint(int aConstraint)
void SetLayer(PCB_LAYER_ID aLayer)
void SetItems(BOARD_ITEM *a, BOARD_ITEM *b=nullptr)
void Reset() override
Rewind for reuse on the next evaluation (see LIBEVAL::CONTEXT::Reset()).
void SetTypeOverride(const BOARD_ITEM *aItem, KICAD_T aType)
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:100
Handle a list of polygons defining a copper zone.
Definition zone.h:70
bool IsTeardropArea() const
Definition zone.h:786
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ F_Cu
Definition layer_ids.h:60
@ RPT_SEVERITY_ERROR
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:101
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:89