25#include <drc_rules_lexer.h>
32using namespace DRCRULE_T;
36 DRC_RULES_LEXER( aSource.
ToStdString(), aSourceDescr ),
46 reportErrorAt( aMessage, CurLineNumber(), CurOffset() + aOffset, CurLine() );
53 wxString first = aMessage.BeforeFirst(
'|', &rest );
57 wxString msg = wxString::Format(
_(
"ERROR: <a href='%d:%d'>%s</a>%s" ),
67 wxString msg = wxString::Format(
_(
"ERROR: %s%s" ), first, rest );
78 wxString msg = wxString::Format(
_(
"The '%s' keyword has been deprecated. "
79 "Please use '%s' instead." ),
90 for(
size_t pos = curText.find(
"${" ); pos != std::string::npos;
91 pos = curText.find(
"${", pos + 2 ) )
93 size_t end = curText.find(
'}', pos + 2 );
95 if(
end != std::string::npos )
97 wxString token = wxString::FromUTF8( curText.substr( pos + 2,
end - ( pos + 2 ) ) );
105 reportError(
_(
"Unresolved text variable" ), (
int) pos );
117 for(
T token = NextTok(); token != T_EOF; token = NextTok() )
119 if( token == T_LEFT )
122 if( token == T_RIGHT )
135 if( curText.starts_with(
"${" ) )
136 msg.Printf(
_(
"Unresolved text variable." ) );
138 msg.Printf(
_(
"Unrecognized item '%s'.| Expected %s." ), FromUTF8(), expectedTokens );
150 for(
T token = NextTok(); token != T_EOF; token = NextTok() )
152 if( token == T_LEFT )
155 if( token == T_RIGHT )
161 if( !expr.IsEmpty() )
162 expr += CurSeparator();
174 bool haveVersion =
false;
178 for(
T token = NextTok(); token != T_EOF; token = NextTok() )
183 if( token != T_LEFT )
188 if( !haveVersion && token != T_version )
228 expected( wxT(
"rule or version" ) );
240 std::vector<std::shared_ptr<COMPONENT_CLASS_ASSIGNMENT_RULE>>& aRules,
REPORTER* aReporter )
242 bool haveVersion =
false;
246 for(
T token = NextTok(); token != T_EOF; token = NextTok() )
248 if( token != T_LEFT )
253 if( !haveVersion && token != T_version )
284 case T_assign_component_class:
293 expected( wxT(
"assign_component_class or version" ) );
306 std::shared_ptr<DRC_RULE> rule = std::make_shared<DRC_RULE>();
307 int conditionLine = 0;
308 int conditionOffset = 0;
309 std::string conditionSource;
313 if( !IsSymbol( token ) )
317 rule->m_Name = FromUTF8();
319 for( token = NextTok(); token != T_RIGHT && token != T_EOF; token = NextTok() )
324 if( token != T_LEFT )
342 else if( IsSymbol( token ) )
346 conditionLine = CurLineNumber();
347 conditionOffset = CurOffset();
348 conditionSource = CurLine();
350 if( !rule->m_Condition->Compile(
m_reporter, CurLineNumber(), CurOffset() ) )
351 reportError( wxString::Format(
_(
"Could not parse expression '%s'." ), FromUTF8() ) );
367 rule->m_LayerCondition =
parseLayer( &rule->m_LayerSource );
379 expected( wxT(
"constraint, condition, or disallow" ) );
386 if( rule->m_Condition && rule->m_Condition->RequiresPairItems() )
391 if( !rule->m_Condition->ReferencesItemB()
402 _(
"Item 'B' is not available for a single-item constraint in rule '%s'." ), rule->m_Name ),
403 conditionLine, conditionOffset, conditionSource.c_str() );
415 std::shared_ptr<DRC_RULE_CONDITION> condition;
419 if( !IsSymbol( token ) )
423 wxString componentClass = FromUTF8();
425 for( token = NextTok(); token != T_RIGHT && token != T_EOF; token = NextTok() )
427 if( token != T_LEFT )
441 else if( IsSymbol( token ) )
444 condition = std::make_shared<DRC_RULE_CONDITION>( FromUTF8() );
446 if( !condition->Compile(
m_reporter, CurLineNumber(), CurOffset() ) )
447 reportError( wxString::Format(
_(
"Could not parse expression '%s'." ), FromUTF8() ) );
471 return std::make_shared<COMPONENT_CLASS_ASSIGNMENT_RULE>( componentClass, std::move( condition ) );
482 bool allowsTimeDomain =
false;
484 auto validateAndSetValueWithUnits =
485 [
this, &allowsTimeDomain, &
unitsType, &c](
int aValue,
const EDA_UNITS aUnits,
auto aSetter )
490 reportError(
_(
"Time based units not allowed for constraint type." ) );
495 reportError(
_(
"Mixed units for constraint values." ) );
501 if( allowsTimeDomain )
521 if( token == T_mechanical_clearance )
524 token = T_physical_clearance;
526 else if( token == T_mechanical_hole_clearance )
528 reportDeprecation( wxT(
"mechanical_hole_clearance" ), wxT(
"physical_hole_clearance" ) );
529 token = T_physical_hole_clearance;
531 else if( token == T_hole )
536 else if( (
int) token ==
DSN_RIGHT || token == T_EOF )
538 msg.Printf(
_(
"Missing constraint type.| Expected %s." ),
539 wxT(
"assertion, clearance, hole_clearance, edge_clearance, physical_clearance, "
540 "physical_hole_clearance, courtyard_clearance, silk_clearance, hole_size, "
541 "hole_to_hole, track_width, track_angle, track_segment_length, annular_width, "
542 "disallow, zone_connection, thermal_relief_gap, thermal_spoke_width, "
543 "min_resolved_spokes, microvia_stack_depth, microvia_aspect_ratio, solder_mask_expansion, "
544 "solder_paste_abs_margin, "
545 "solder_paste_rel_margin, length, net_chain_length, skew, via_count, "
546 "via_dangling, via_diameter, diff_pair_gap or diff_pair_uncoupled" ) );
595 expected( wxT(
"assertion, clearance, hole_clearance, edge_clearance, physical_clearance, "
596 "physical_hole_clearance, courtyard_clearance, silk_clearance, hole_size, "
597 "hole_to_hole, track_width, track_angle, track_segment_length, annular_width, "
598 "disallow, zone_connection, thermal_relief_gap, thermal_spoke_width, "
599 "min_resolved_spokes, microvia_stack_depth, microvia_aspect_ratio, solder_mask_expansion, "
600 "solder_mask_sliver, "
601 "solder_paste_abs_margin, solder_paste_rel_margin, length, net_chain_length, "
602 "skew, via_count, via_dangling, via_diameter, diff_pair_gap, "
603 "diff_pair_uncoupled or bridged_mask" ) );
609 msg.Printf(
_(
"Rule already has a '%s' constraint." ), FromUTF8() );
625 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
628 token = GetCurStrAsToken();
653 expected( wxT(
"track, via, through_via, blind_via, micro_via, buried_via, pad, zone, text, "
654 "graphic, hole, or footprint." ) );
668 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
670 if( token == T_LEFT )
676 NeedSYMBOLorNUMBER();
682 NeedSYMBOLorNUMBER();
693 while( NextTok() != T_RIGHT )
707 token = GetCurStrAsToken();
720 expected( wxT(
"solid, thermal_reliefs or none." ) );
741 value = (int) strtol( CurText(),
nullptr, 10 );
762 if( IsSymbol( token ) )
768 reportError(
_(
"Item 'B' is not available in assertion expressions." ) );
782 for( token = NextTok(); token != T_RIGHT && token != T_EOF; token = NextTok() )
784 if( token != T_LEFT )
791 case T_within_diff_pairs:
795 reportError(
_(
"within_diff_pairs option invalid for constraint type." ) );
804 size_t offset = CurOffset() + GetTokenString( token ).length();
814 validateAndSetValueWithUnits( value, units,
815 [&c](
const int aValue )
825 size_t offset = CurOffset() + GetTokenString( token ).length();
835 validateAndSetValueWithUnits( value, units,
836 [&c](
const int aValue )
846 size_t offset = CurOffset() + GetTokenString( token ).length();
856 validateAndSetValueWithUnits( value, units,
857 [&c](
const int aValue )
870 expected( wxT(
"min, max, opt, or within_diff_pairs" ) );
879 bool aUnitless,
bool aRatio )
885 [&](
const wxString&
message,
int offset )
888 wxString first =
message.BeforeFirst(
'|', &rest );
892 wxString msg = wxString::Format(
_(
"ERROR: <a href='%d:%d'>%s</a>%s" ),
902 wxString msg = wxString::Format(
_(
"ERROR: %s%s" ), first, rest );
905 CurOffset() + aOffset );
917 aUnits = evaluator.
Units();
925 int token = NextTok();
932 else if( token == T_outer )
934 *aSource = GetTokenString( token );
937 else if( token == T_inner )
939 *aSource = GetTokenString( token );
944 wxString layerName = FromUTF8();
947 for(
unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
949 wxPGChoiceEntry& entry = layerMap[ii];
951 if( entry.GetText().Matches( layerName ) )
953 *aSource = layerName;
961 reportError( wxString::Format(
_(
"Unrecognized layer '%s'." ), layerName ) );
980 if( (
int) token ==
DSN_RIGHT || token == T_EOF )
994 expected( wxT(
"ignore, warning, error, or exclusion" ) );
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
BASE_SET & set(size_t pos)
DRC_RULE_CONDITION * m_Test
void SetOption(OPTIONS option)
ZONE_CONNECTION m_ZoneConnection
wxString m_ReferenceLayer
void ClearOption(OPTIONS option)
wxString parseExpression()
std::shared_ptr< COMPONENT_CLASS_ASSIGNMENT_RULE > parseComponentClassAssignment()
void reportDeprecation(const wxString &oldToken, const wxString &newToken)
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
void reportError(const wxString &aMessage, int aOffset=0)
void parseValueWithUnits(int aOffset, const wxString &aExpr, int &aResult, EDA_UNITS &aUnits, bool aUnitless=false, bool aRatio=false)
void ParseComponentClassAssignmentRules(std::vector< std::shared_ptr< COMPONENT_CLASS_ASSIGNMENT_RULE > > &aRules, REPORTER *aReporter)
void expected(const wxString &expectedTokens)
bool checkUnresolvedTextVariable()
std::shared_ptr< DRC_RULE > parseDRC_RULE()
LSET parseLayer(wxString *aSource)
void parseConstraint(DRC_RULE *aRule)
void reportErrorAt(const wxString &aMessage, int aLine, int aOffset, const char *aSourceLine)
DRC_RULES_PARSER(const wxString &aSource, const wxString &aSourceDescr)
bool Compile(REPORTER *aReporter, int aSourceLine=0, int aSourceOffset=0)
bool RequiresPairItems() const
void AddConstraint(DRC_CONSTRAINT &aConstraint)
std::optional< DRC_CONSTRAINT > FindConstraint(DRC_CONSTRAINT_T aType)
static ENUM_MAP< T > & Instance()
LSET is a set of PCB_LAYER_IDs.
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
static const LSET & ExternalCuMask()
Return a mask holding the Front and Bottom layers.
static const LSET & AllLayersMask()
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
double ResultAsDouble() const
Unrounded result, for constraints whose value is a ratio rather than a count or a length.
bool Evaluate(const wxString &aExpr)
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
A pure virtual class used to derive REPORTER objects from.
static EDA_DATA_TYPE GetTypeFromUnits(const EDA_UNITS aUnits)
Gets the inferred type from the given units.
bool IsComponentClassSelector(const wxString &aToken)
${Class:X} inside a DRC rule is a component-class selector consumed by testFootprintSelector(),...
@ DRC_DISALLOW_BURIED_VIAS
@ DRC_DISALLOW_BLIND_VIAS
@ DRC_DISALLOW_THROUGH_VIAS
@ DRC_DISALLOW_FOOTPRINTS
@ DRC_DISALLOW_MICRO_VIAS
@ ANNULAR_WIDTH_CONSTRAINT
@ BRIDGED_MASK_CONSTRAINT
@ COURTYARD_CLEARANCE_CONSTRAINT
@ VIA_DIAMETER_CONSTRAINT
@ ZONE_CONNECTION_CONSTRAINT
@ DIFF_PAIR_GAP_CONSTRAINT
@ NET_CHAIN_LENGTH_CONSTRAINT
@ VIA_DANGLING_CONSTRAINT
@ SOLDER_MASK_SLIVER_CONSTRAINT
@ NET_CHAIN_STUB_LENGTH_CONSTRAINT
@ SILK_CLEARANCE_CONSTRAINT
@ EDGE_CLEARANCE_CONSTRAINT
@ MIN_RESOLVED_SPOKES_CONSTRAINT
@ TRACK_SEGMENT_LENGTH_CONSTRAINT
@ TEXT_THICKNESS_CONSTRAINT
@ NET_CHAIN_RETURN_PATH_CONSTRAINT
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
@ MICROVIA_ASPECT_RATIO_CONSTRAINT
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
@ CONNECTION_WIDTH_CONSTRAINT
@ THERMAL_RELIEF_GAP_CONSTRAINT
@ MAX_UNCOUPLED_CONSTRAINT
@ MICROVIA_STACK_DEPTH_CONSTRAINT
@ HOLE_CLEARANCE_CONSTRAINT
@ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
@ SOLDER_MASK_EXPANSION_CONSTRAINT
@ PHYSICAL_CLEARANCE_CONSTRAINT
@ SOLDER_PASTE_REL_MARGIN_CONSTRAINT
@ HOLE_TO_HOLE_CONSTRAINT
#define DRC_RULE_FILE_VERSION
static std::string ToStdString(const wxString &aStr)
EDA_DATA_TYPE
The type of unit.
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
PCB_LAYER_ID ToLAYER_ID(int aLayer)
VECTOR3I expected(15, 30, 45)
@ THERMAL
Use thermal relief for pads.
@ NONE
Pads are not covered.
@ FULL
pads are covered by copper