KiCad PCB EDA Suite
Loading...
Searching...
No Matches
corpus.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 "corpus.h"
21
22#include <fstream>
23#include <sstream>
24
25#include <wx/filename.h>
26#include <wx/utils.h>
27
28#include <json_common.h>
29
30
32{
33 wxString root;
34
35 if( !wxGetEnv( wxT( "KICAD_DRC_BENCH_CORPUS" ), &root ) || root.IsEmpty() )
36 return false;
37
38 return wxFileName::DirExists( root );
39}
40
41
42wxString CORPUS::Root()
43{
44 wxString root;
45
46 if( !wxGetEnv( wxT( "KICAD_DRC_BENCH_CORPUS" ), &root ) )
47 return wxEmptyString;
48
49 return root;
50}
51
52
54static wxString resolveAgainstRoot( const wxString& aRoot, const wxString& aRelative )
55{
56 if( aRelative.IsEmpty() )
57 return wxEmptyString;
58
59 wxFileName fn( aRelative );
60
61 if( fn.IsAbsolute() )
62 return fn.GetFullPath();
63
64 wxFileName resolved( aRoot, wxEmptyString );
65 resolved.SetFullName( wxEmptyString );
66
67 wxFileName joined( aRoot + wxFileName::GetPathSeparator() + aRelative );
68 joined.MakeAbsolute();
69
70 return joined.GetFullPath();
71}
72
73
74bool CORPUS::Load( std::vector<CORPUS_ENTRY>& aEntries, wxString& aError )
75{
76 aEntries.clear();
77 aError.clear();
78
79 if( !IsConfigured() )
80 return true;
81
82 wxString root = Root();
83 wxFileName manifest( root, wxT( "corpus.json" ) );
84
85 if( !manifest.Exists() )
86 {
87 aError = wxString::Format( wxT( "corpus.json not found in %s" ), root );
88 return false;
89 }
90
91 std::ifstream in( manifest.GetFullPath().fn_str() );
92
93 if( !in.is_open() )
94 {
95 aError = wxString::Format( wxT( "cannot open %s" ), manifest.GetFullPath() );
96 return false;
97 }
98
99 std::stringstream buffer;
100 buffer << in.rdbuf();
101
102 nlohmann::json doc;
103
104 try
105 {
106 doc = nlohmann::json::parse( buffer.str() );
107 }
108 catch( const std::exception& e )
109 {
110 aError = wxString::Format( wxT( "corpus.json parse error: %s" ), e.what() );
111 return false;
112 }
113
114 if( !doc.is_array() )
115 {
116 aError = wxT( "corpus.json must be a JSON array of entries" );
117 return false;
118 }
119
120 for( const nlohmann::json& node : doc )
121 {
122 if( !node.is_object() || !node.contains( "board" ) )
123 continue;
124
125 CORPUS_ENTRY entry;
126
127 auto getString = [&]( const char* aKey ) -> wxString
128 {
129 if( node.contains( aKey ) && node[aKey].is_string() )
130 return wxString::FromUTF8( node[aKey].get<std::string>().c_str() );
131
132 return wxEmptyString;
133 };
134
135 entry.board = resolveAgainstRoot( root, getString( "board" ) );
136 entry.rules = resolveAgainstRoot( root, getString( "rules" ) );
137 entry.tier = getString( "tier" );
138 entry.source = getString( "source" );
139 entry.notes = getString( "notes" );
140
141 if( node.contains( "quick" ) && node["quick"].is_boolean() )
142 entry.quick = node["quick"].get<bool>();
143
144 aEntries.push_back( entry );
145 }
146
147 return true;
148}
149
150
152{
153 switch( aType )
154 {
155 case NULL_CONSTRAINT: return "null";
156 case CLEARANCE_CONSTRAINT: return "clearance";
157 case CREEPAGE_CONSTRAINT: return "creepage";
158 case HOLE_CLEARANCE_CONSTRAINT: return "hole_clearance";
159 case HOLE_TO_HOLE_CONSTRAINT: return "hole_to_hole";
160 case EDGE_CLEARANCE_CONSTRAINT: return "edge_clearance";
161 case HOLE_SIZE_CONSTRAINT: return "hole_size";
162 case COURTYARD_CLEARANCE_CONSTRAINT: return "courtyard_clearance";
163 case SILK_CLEARANCE_CONSTRAINT: return "silk_clearance";
164 case TEXT_HEIGHT_CONSTRAINT: return "text_height";
165 case TEXT_THICKNESS_CONSTRAINT: return "text_thickness";
166 case TRACK_WIDTH_CONSTRAINT: return "track_width";
167 case TRACK_SEGMENT_LENGTH_CONSTRAINT: return "track_segment_length";
168 case ANNULAR_WIDTH_CONSTRAINT: return "annular_width";
169 case ZONE_CONNECTION_CONSTRAINT: return "zone_connection";
170 case THERMAL_RELIEF_GAP_CONSTRAINT: return "thermal_relief_gap";
171 case THERMAL_SPOKE_WIDTH_CONSTRAINT: return "thermal_spoke_width";
172 case MIN_RESOLVED_SPOKES_CONSTRAINT: return "min_resolved_spokes";
173 case SOLDER_MASK_EXPANSION_CONSTRAINT: return "solder_mask_expansion";
174 case SOLDER_PASTE_ABS_MARGIN_CONSTRAINT: return "solder_paste_abs_margin";
175 case SOLDER_PASTE_REL_MARGIN_CONSTRAINT: return "solder_paste_rel_margin";
176 case DISALLOW_CONSTRAINT: return "disallow";
177 case VIA_DIAMETER_CONSTRAINT: return "via_diameter";
178 case LENGTH_CONSTRAINT: return "length";
179 case NET_CHAIN_LENGTH_CONSTRAINT: return "net_chain_length";
180 case NET_CHAIN_STUB_LENGTH_CONSTRAINT: return "net_chain_stub_length";
181 case NET_CHAIN_RETURN_PATH_CONSTRAINT: return "net_chain_return_path";
182 case SKEW_CONSTRAINT: return "skew";
183 case DIFF_PAIR_GAP_CONSTRAINT: return "diff_pair_gap";
184 case MAX_UNCOUPLED_CONSTRAINT: return "max_uncoupled";
185 case DIFF_PAIR_INTRA_SKEW_CONSTRAINT: return "diff_pair_intra_skew";
186 case VIA_COUNT_CONSTRAINT: return "via_count";
187 case PHYSICAL_CLEARANCE_CONSTRAINT: return "physical_clearance";
188 case PHYSICAL_HOLE_CLEARANCE_CONSTRAINT: return "physical_hole_clearance";
189 case ASSERTION_CONSTRAINT: return "assertion";
190 case CONNECTION_WIDTH_CONSTRAINT: return "connection_width";
191 case TRACK_ANGLE_CONSTRAINT: return "track_angle";
192 case VIA_DANGLING_CONSTRAINT: return "via_dangling";
193 case BRIDGED_MASK_CONSTRAINT: return "bridged_mask";
194 case SOLDER_MASK_SLIVER_CONSTRAINT: return "solder_mask_sliver";
195 case MICROVIA_STACK_DEPTH_CONSTRAINT: return "microvia_stack_depth";
196 case MICROVIA_ASPECT_RATIO_CONSTRAINT: return "microvia_aspect_ratio";
197 }
198
199 return "?";
200}
201
202
249
250
251const std::vector<wxString>& AllPredicateNames()
252{
253 // Mirrors the RegisterFunc entries in pcbexpr_functions.cpp. The expensive geometry and
254 // per-item lookups the optimizer watches are listed first for readability, but the order is
255 // not load-bearing.
256 static const std::vector<wxString> names = { wxT( "intersectsCourtyard" ),
257 wxT( "intersectsFrontCourtyard" ),
258 wxT( "intersectsBackCourtyard" ),
259 wxT( "insideCourtyard" ),
260 wxT( "insideFrontCourtyard" ),
261 wxT( "insideBackCourtyard" ),
262 wxT( "intersectsArea" ),
263 wxT( "intersectsKeepout" ),
264 wxT( "enclosedByArea" ),
265 wxT( "insideArea" ),
266 wxT( "getField" ),
267 wxT( "hasNetclass" ),
268 wxT( "hasExactNetclass" ),
269 wxT( "hasComponentClass" ),
270 wxT( "memberOf" ),
271 wxT( "memberOfSheet" ),
272 wxT( "memberOfSheetOrChildren" ),
273 wxT( "memberOfFootprint" ),
274 wxT( "memberOfGroup" ),
275 wxT( "fromTo" ),
276 wxT( "inDiffPair" ),
277 wxT( "isCoupledDiffPair" ),
278 wxT( "inNetChain" ),
279 wxT( "inNetChainClass" ),
280 wxT( "hasNetChain" ),
281 wxT( "existsOnLayer" ),
282 wxT( "isPlated" ),
283 wxT( "isMicroVia" ),
284 wxT( "isBlindVia" ),
285 wxT( "isBuriedVia" ),
286 wxT( "isBlindBuriedVia" ),
287 wxT( "isStackedVia" ) };
288
289 return names;
290}
291
292
293std::vector<wxString> ScanPredicatesInRules( const wxString& aRulesText )
294{
295 std::vector<wxString> found;
296
297 for( const wxString& name : AllPredicateNames() )
298 {
299 // The grammar always invokes a predicate as name( ... ), so anchor on the open paren to
300 // avoid matching a predicate name that only appears inside a comment or a longer token.
301 size_t searchFrom = 0;
302
303 while( true )
304 {
305 size_t pos = aRulesText.find( name, searchFrom );
306
307 if( pos == wxString::npos )
308 break;
309
310 size_t after = pos + name.length();
311
312 while( after < aRulesText.length() && wxIsspace( aRulesText[after] ) )
313 ++after;
314
315 if( after < aRulesText.length() && aRulesText[after] == '(' )
316 {
317 found.push_back( name );
318 break;
319 }
320
321 searchFrom = pos + 1;
322 }
323 }
324
325 return found;
326}
const char * name
static bool Load(std::vector< CORPUS_ENTRY > &aEntries, wxString &aError)
Parse <root>/corpus.json into resolved entries.
Definition corpus.cpp:74
static bool IsConfigured()
True when KICAD_DRC_BENCH_CORPUS is set and names an existing directory.
Definition corpus.cpp:31
static wxString Root()
The resolved corpus root, or an empty string when unconfigured.
Definition corpus.cpp:42
const char * ConstraintTypeName(DRC_CONSTRAINT_T aType)
Human-readable token for a DRC_CONSTRAINT_T, matching the .kicad_dru keyword where one exists.
Definition corpus.cpp:151
std::vector< wxString > ScanPredicatesInRules(const wxString &aRulesText)
Scan raw .kicad_dru text for occurrences of each registered predicate name.
Definition corpus.cpp:293
const std::vector< wxString > & AllPredicateNames()
Every pcbexpr predicate registered in pcbexpr_functions.cpp, used for textual coverage scans.
Definition corpus.cpp:251
static wxString resolveAgainstRoot(const wxString &aRoot, const wxString &aRelative)
Resolve a manifest-relative path against the corpus root and return an absolute path.
Definition corpus.cpp:54
const std::vector< DRC_CONSTRAINT_T > & AllConstraintTypes()
Every DRC_CONSTRAINT_T the engine can carry rules for, in enum order, excluding NULL_CONSTRAINT.
Definition corpus.cpp:203
DRC_CONSTRAINT_T
Definition drc_rule.h:49
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:63
@ BRIDGED_MASK_CONSTRAINT
Definition drc_rule.h:88
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition drc_rule.h:57
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:72
@ ZONE_CONNECTION_CONSTRAINT
Definition drc_rule.h:64
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:78
@ NET_CHAIN_LENGTH_CONSTRAINT
Definition drc_rule.h:74
@ VIA_DANGLING_CONSTRAINT
Definition drc_rule.h:87
@ SOLDER_MASK_SLIVER_CONSTRAINT
Definition drc_rule.h:89
@ NET_CHAIN_STUB_LENGTH_CONSTRAINT
Definition drc_rule.h:75
@ DISALLOW_CONSTRAINT
Definition drc_rule.h:71
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ SILK_CLEARANCE_CONSTRAINT
Definition drc_rule.h:58
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ MIN_RESOLVED_SPOKES_CONSTRAINT
Definition drc_rule.h:67
@ TRACK_SEGMENT_LENGTH_CONSTRAINT
Definition drc_rule.h:62
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:60
@ LENGTH_CONSTRAINT
Definition drc_rule.h:73
@ VIA_COUNT_CONSTRAINT
Definition drc_rule.h:81
@ NET_CHAIN_RETURN_PATH_CONSTRAINT
Definition drc_rule.h:76
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:83
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ MICROVIA_ASPECT_RATIO_CONSTRAINT
Definition drc_rule.h:91
@ NULL_CONSTRAINT
Definition drc_rule.h:50
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
Definition drc_rule.h:66
@ CONNECTION_WIDTH_CONSTRAINT
Definition drc_rule.h:85
@ THERMAL_RELIEF_GAP_CONSTRAINT
Definition drc_rule.h:65
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:79
@ ASSERTION_CONSTRAINT
Definition drc_rule.h:84
@ SKEW_CONSTRAINT
Definition drc_rule.h:77
@ MICROVIA_STACK_DEPTH_CONSTRAINT
Definition drc_rule.h:90
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
Definition drc_rule.h:69
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:68
@ TRACK_ANGLE_CONSTRAINT
Definition drc_rule.h:86
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:56
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:59
@ CREEPAGE_CONSTRAINT
Definition drc_rule.h:52
@ DIFF_PAIR_INTRA_SKEW_CONSTRAINT
Definition drc_rule.h:80
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:82
@ SOLDER_PASTE_REL_MARGIN_CONSTRAINT
Definition drc_rule.h:70
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:54
One board+rules pairing from the out-of-tree corpus manifest.
Definition corpus.h:36
wxString tier
Free-form tier tag from the manifest (A/B/C).
Definition corpus.h:39
wxString board
Absolute path to the .kicad_pcb.
Definition corpus.h:37
wxString rules
Absolute path to the .kicad_dru, or empty for none.
Definition corpus.h:38
wxString source
Provenance string for traceability.
Definition corpus.h:40
wxString notes
Free-form annotation.
Definition corpus.h:41
bool quick
Part of the fast iteration set selected by –quick.
Definition corpus.h:42