182 size_t pos = aBlock.find(
"(rule" );
184 if( pos == std::string::npos )
185 return wxEmptyString;
189 while( pos < aBlock.size() && std::isspace(
static_cast<unsigned char>( aBlock[pos] ) ) )
192 if( pos >= aBlock.size() )
193 return wxEmptyString;
197 if( aBlock[pos] ==
'"' )
199 for( pos++; pos < aBlock.size() && aBlock[pos] !=
'"'; pos++ )
201 if( aBlock[pos] ==
'\\' && pos + 1 < aBlock.size() )
209 while( pos < aBlock.size() && !std::isspace(
static_cast<unsigned char>( aBlock[pos] ) ) && aBlock[pos] !=
'('
210 && aBlock[pos] !=
')' )
212 name += aBlock[pos++];
216 return wxString::FromUTF8(
name.c_str() );
273 std::string conditions;
275 std::vector<std::string> nodes;
277 for(
size_t i = 0; i < block.size(); i++ )
279 if( block[i] ==
'(' )
283 while( i < block.size() && !std::isspace(
static_cast<unsigned char>( block[i] ) ) && block[i] !=
'('
287 std::string node = block.substr( start, i - start );
289 if( node ==
"constraint" )
293 while( kind < block.size() && std::isspace(
static_cast<unsigned char>( block[kind] ) ) )
298 while(
end < block.size() && !std::isspace(
static_cast<unsigned char>( block[
end] ) )
299 && block[
end] !=
'(' && block[
end] !=
')' )
304 if( block.substr( kind,
end - kind ) ==
"assertion" )
308 nodes.push_back( std::move( node ) );
311 else if( block[i] ==
')' )
316 else if( block[i] ==
'"' )
320 while( ++i < block.size() && block[i] !=
'"' )
322 if( block[i] ==
'\\' && i + 1 < block.size() )
328 if( !nodes.empty() && ( nodes.back() ==
"condition" || nodes.back() ==
"assertion" ) )
332 for(
size_t j = 0; j < value.size(); j++ )
338 if( c ==
'\\' && j + 1 < value.size() )
340 else if( c == quote )
343 else if( c ==
'\'' || c ==
'"' )
356 else if( !nodes.empty() && ( nodes.back() ==
"min" || nodes.back() ==
"max" || nodes.back() ==
"opt" ) )
358 values += value +
'\n';
364 size_t name = block.find(
"(rule" );
366 if(
name != std::string::npos )
370 while(
name < block.size() && std::isspace(
static_cast<unsigned char>( block[
name] ) ) )
373 if(
name < block.size() && block[
name] !=
'"' )
377 while(
end < block.size() && !std::isspace(
static_cast<unsigned char>( block[
end] ) ) && block[
end] !=
'('
378 && block[
end] !=
')' )
387 std::string foldedConditions = conditions;
389 for(
char& c : foldedConditions )
390 c =
static_cast<char>( std::tolower(
static_cast<unsigned char>( c ) ) );
400 std::string function = token.m_token;
402 for(
char& c : function )
403 c =
static_cast<char>( std::tolower(
static_cast<unsigned char>( c ) ) );
405 for(
size_t pos = foldedConditions.find( function ); pos != std::string::npos;
406 pos = foldedConditions.find( function, pos + 1 ) )
409 && ( std::isalnum(
static_cast<unsigned char>( foldedConditions[pos - 1] ) )
410 || foldedConditions[pos - 1] ==
'_' ) )
413 size_t after = pos + function.size();
415 while( after < foldedConditions.size()
416 && std::isspace(
static_cast<unsigned char>( foldedConditions[after] ) ) )
419 if( after < foldedConditions.size() && foldedConditions[after] ==
'(' )
424 for(
size_t pos = 0; pos < foldedConditions.size(); pos++ )
426 if( foldedConditions[pos] !=
'.' )
429 size_t begin = pos + 1;
431 while( begin < foldedConditions.size()
432 && std::isspace(
static_cast<unsigned char>( foldedConditions[begin] ) ) )
439 while(
end < foldedConditions.size()
440 && ( std::isalnum(
static_cast<unsigned char>( foldedConditions[
end] ) )
441 || foldedConditions[
end] ==
'_' ) )
446 const std::string
property = foldedConditions.substr( begin,
end - begin );
449 if( property ==
"parent" )
453 while(
next < foldedConditions.size()
454 && std::isspace(
static_cast<unsigned char>( foldedConditions[
next] ) ) )
459 if(
next < foldedConditions.size() && foldedConditions[
next] ==
'.' )
465 if( aTarget.
m_boardVersion < token.m_introducedIn && property == token.m_token )
469 pos =
end > begin ?
end - 1 : pos;
477 return std::isalnum(
static_cast<unsigned char>( c ) ) || c ==
'_';
480 const std::string numeric = structural +
'\n' + values + conditions;
482 for(
size_t i = 1; i + 1 < numeric.size(); i++ )
486 while( before > 0 && std::isspace(
static_cast<unsigned char>( numeric[before - 1] ) ) )
490 || ( !std::isdigit(
static_cast<unsigned char>( numeric[before - 1] ) )
491 && numeric[before - 1] !=
'.' ) )
494 if( ( numeric[i] ==
'f' || numeric[i] ==
'p' ) && numeric[i + 1] ==
's'
495 && ( i + 2 >= numeric.size() || !
isWordChar( numeric[i + 2] ) ) )
500 if( numeric.compare( i, 3,
"deg" ) == 0 && ( i + 3 >= numeric.size() || !
isWordChar( numeric[i + 3] ) ) )
527 std::string
text = aRulesText.ToStdString( wxConvUTF8 );
530 result.m_text = wxT(
"(version 1)\n" );
534 while( i <
text.size() )
537 size_t prefixStart = i;
539 while( i <
text.size() &&
text[i] !=
'(' )
545 result.m_error =
_(
"Design rule comments must start on a separate line." );
549 while( i <
text.size() &&
text[i] !=
'\n' )
558 if( i >=
text.size() )
561 std::string prefix =
text.substr( prefixStart, i - prefixStart );
563 size_t blockStart = i;
565 bool inString =
false;
567 for( ; i <
text.size(); i++ )
573 if( c ==
'\\' && i + 1 <
text.size() )
589 result.m_error =
_(
"Design rule comments must start on a separate line." );
593 while( i <
text.size() &&
text[i] !=
'\n' )
600 else if( c ==
')' && --depth == 0 )
607 std::string block =
text.substr( blockStart, i - blockStart );
609 if( depth != 0 || inString )
611 result.m_error =
_(
"Unbalanced parentheses or unterminated string in design rules." );
616 if( block.compare( 0, 8,
"(version" ) == 0 )
619 bool isRule = block.compare( 0, 5,
"(rule" ) == 0
620 && ( block.size() <= 5
621 || ( !std::isalnum(
static_cast<unsigned char>( block[5] ) ) && block[5] !=
'_' ) );
629 result.m_text += wxString::FromUTF8( ( prefix + block ).c_str() );
632 result.m_text += wxT(
"\n" );
bool ContainsSexprValue(const std::string &aText, const std::string &aToken)
Some features are written as a bareword value, not a node head, so the node scan cannot see them.
wxString result
Test unit parsing edge cases and error handling.