From 577c1be39175b724799f2fd65c7581397d5571b7 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Thu, 30 Jul 2020 12:24:29 +0100 Subject: [PATCH] Report all DRC rule errors, not just the first. --- common/drc_rules.keywords | 4 - common/libeval_compiler/libeval_compiler.cpp | 128 ++++----- include/libeval_compiler/libeval_compiler.h | 31 +-- pcbnew/dialogs/panel_setup_rules.cpp | 49 +++- pcbnew/dialogs/panel_setup_rules.h | 2 + pcbnew/dialogs/panel_setup_rules_base.cpp | 22 +- pcbnew/dialogs/panel_setup_rules_base.fbp | 145 +++++++++- pcbnew/dialogs/panel_setup_rules_base.h | 12 + pcbnew/drc/drc.cpp | 4 +- pcbnew/drc/drc_rule.cpp | 57 +--- pcbnew/drc/drc_rule.h | 4 +- pcbnew/drc/drc_rule_parser.cpp | 277 +++++++++++++++---- pcbnew/drc/drc_rule_parser.h | 12 +- pcbnew/pcb_expr_evaluator.cpp | 36 +-- pcbnew/pcb_expr_evaluator.h | 15 +- qa/drc_proto/drc_engine.cpp | 6 +- qa/drc_proto/drc_rule.cpp | 18 +- qa/drc_proto/drc_rule.h | 6 +- qa/drc_proto/drc_rule_parser.cpp | 209 +++++++++++--- qa/drc_proto/drc_rule_parser.h | 19 +- qa/drc_proto/drc_rules_proto.keywords | 7 +- 21 files changed, 744 insertions(+), 319 deletions(-) diff --git a/common/drc_rules.keywords b/common/drc_rules.keywords index 6fcea5f956..664b79affa 100644 --- a/common/drc_rules.keywords +++ b/common/drc_rules.keywords @@ -10,10 +10,6 @@ graphic hole inner layer -match_area -match_layer -match_netclass -match_type max micro_via min diff --git a/common/libeval_compiler/libeval_compiler.cpp b/common/libeval_compiler/libeval_compiler.cpp index b0ecb510cf..f508770ef4 100644 --- a/common/libeval_compiler/libeval_compiler.cpp +++ b/common/libeval_compiler/libeval_compiler.cpp @@ -26,6 +26,7 @@ #include #endif +#include #include /* The (generated) lemon parser is written in C. @@ -150,13 +151,6 @@ std::string UCODE::Dump() const }; -void CONTEXT::ReportError( const wxString& aErrorMsg ) -{ - m_errorStatus.pendingError = true; - m_errorStatus.message = aErrorMsg; -} - - std::string TOKENIZER::GetChars( std::function cond ) const { std::string rv; @@ -186,7 +180,10 @@ bool TOKENIZER::MatchAhead( const std::string& match, std::function } -COMPILER::COMPILER() +COMPILER::COMPILER( REPORTER* aReporter, int aSourceLine, int aSourceOffset ) : + m_reporter( aReporter ), + m_originLine( aSourceLine ), + m_originOffset( aSourceOffset ) { m_localeDecimalSeparator = '.'; m_sourcePos = 0; @@ -224,9 +221,7 @@ void COMPILER::Clear() void COMPILER::parseError( const char* s ) { - libeval_dbg(0, "PARSE ERROR: %s\n", s ); - m_errorStatus.pendingError = true; - m_errorStatus.message = s; + reportError( s ); } @@ -241,7 +236,6 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode, CONTEXT* aPref // Feed parser token after token until end of input. newString( aString ); - m_errorStatus.pendingError = false; if( m_tree ) { @@ -268,14 +262,6 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode, CONTEXT* aPref libeval_dbg(10, "parse: tok %d\n", tok.token ); Parse( m_parser, tok.token, tok.value, this ); - if( m_errorStatus.pendingError ) - { - m_errorStatus.stage = ERROR_STATUS::CST_PARSE; - m_errorStatus.message.Printf( _( "Unrecognized token '%s'" ), tok.value.value.str ); - m_errorStatus.srcPos = m_tokenizer.GetPos(); - return false; - } - if( m_parseFinished || tok.token == G_ENDS ) { // Reset parser by passing zero as token ID, value is ignored. @@ -359,6 +345,7 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken ) T_TOKEN retval; std::string current; int convertFrom; + wxString msg; retval.token = G_ENDS; @@ -495,8 +482,6 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken ) } else { - //printf( "WTF: '%c'\n", ch ); - // Single char tokens switch( ch ) { @@ -513,9 +498,7 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken ) case '.': retval.token = G_STRUCT_REF; break; default: - m_errorStatus.stage = ERROR_STATUS::CST_PARSE; - m_errorStatus.message.Printf( _( "Unrecognized character '%c'" ), (char) ch ); - m_errorStatus.srcPos = m_tokenizer.GetPos(); + reportError( wxString::Format( _( "Unrecognized character '%c'" ), (char) ch ) ); break; } @@ -526,6 +509,7 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken ) return true; } + const std::string formatNode( TREE_NODE* tok ) { // printf("fmt tok %p v %p ", tok, tok->value.v ); @@ -598,10 +582,20 @@ void dumpNode( std::string& buf, TREE_NODE* tok, int depth = 0 ) } -void COMPILER::ReportError( const wxString& aErrorMsg ) +void COMPILER::reportError( const wxString& aErrorMsg, int aPos ) { - m_errorStatus.pendingError = true; - m_errorStatus.message = aErrorMsg; + if( aPos == -1 ) + aPos = m_sourcePos; + + wxString rest; + wxString first = aErrorMsg.BeforeFirst( '|', &rest ); + wxString msg = wxString::Format( _( "ERROR: %s%s" ), + m_originLine, + m_originOffset + aPos, + first, + rest ); + + m_reporter->Report( msg, RPT_SEVERITY_ERROR ); } @@ -624,6 +618,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) { std::vector stack; std::set visitedNodes; + wxString msg; auto visited = [&]( TREE_NODE* node ) -> bool { @@ -663,26 +658,19 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) { char* itemName = node->leaf[0]->value.str; char* propName = node->leaf[1]->value.str; - VAR_REF* vref = aCode->createVarRef( this, itemName, propName ); + VAR_REF* vref = aCode->CreateVarRef( itemName, propName ); - if( m_errorStatus.pendingError ) + if( !vref ) { - m_errorStatus.pendingError = true; - m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN; - - if( m_errorStatus.message == "var" ) - { - m_errorStatus.message.Printf( _( "Unrecognized item '%s'" ), - itemName ); - m_errorStatus.srcPos = node->leaf[0]->srcPos - strlen( itemName ); - } - else - { - m_errorStatus.message.Printf( _( "Unrecognized property '%s'" ), - propName ); - m_errorStatus.srcPos = node->leaf[1]->srcPos - strlen( propName ); - } + msg.Printf( _( "Unrecognized item '%s'" ), itemName ); + reportError( msg, node->leaf[0]->srcPos - (int) strlen( itemName ) ); + return false; + } + if( vref->GetType() == VT_PARSE_ERROR ) + { + msg.Printf( _( "Unrecognized property '%s'" ), propName ); + reportError( msg, node->leaf[1]->srcPos - (int) strlen( propName ) ); return false; } @@ -693,26 +681,22 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) case TR_OP_FUNC_CALL: { char* itemName = node->leaf[0]->value.str; - VAR_REF* vref = aCode->createVarRef( this, itemName, "" ); + VAR_REF* vref = aCode->CreateVarRef( itemName, "" ); - if( m_errorStatus.pendingError ) + if( !vref ) { - m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN; - m_errorStatus.message.Printf( _( "Unrecognized item '%s'" ), itemName ); - m_errorStatus.srcPos = node->leaf[0]->srcPos - strlen( itemName ); + msg.Printf( _( "Unrecognized item '%s'" ), itemName ); + reportError( msg, node->leaf[0]->srcPos - (int) strlen( itemName ) ); return false; } char* functionName = node->leaf[1]->leaf[0]->value.str; - auto func = aCode->createFuncCall( this, functionName ); + auto func = aCode->CreateFuncCall( functionName ); if( !func ) { - m_errorStatus.pendingError = true; - m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN; - m_errorStatus.message.Printf( _( "Unrecognized function '%s'" ), - functionName ); - m_errorStatus.srcPos = node->leaf[1]->leaf[0]->srcPos + 1; + msg.Printf( _( "Unrecognized function '%s'" ), functionName ); + reportError( msg, node->leaf[1]->leaf[0]->srcPos + 1 ); return false; } @@ -730,18 +714,18 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) { } - if( aPreflightContext->GetErrorStatus().pendingError ) - { - m_errorStatus = aPreflightContext->GetErrorStatus(); - m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN; - m_errorStatus.srcPos = node->leaf[1]->leaf[0]->srcPos + 1; - return false; - } - /* SREF -> FUNC_CALL -> leaf0/1 */ node->leaf[1]->leaf[0]->leaf[0] = nullptr; node->leaf[1]->leaf[0]->leaf[1] = nullptr; + if( !aPreflightContext->GetError().IsEmpty() ) + { + reportError( aPreflightContext->GetError(), + node->leaf[1]->leaf[1]->srcPos + - (int) strlen( node->value.str ) - 1 ); + return false; + } + visitedNodes.insert( node->leaf[0] ); visitedNodes.insert( node->leaf[1]->leaf[0] ); @@ -782,20 +766,12 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) case TR_IDENTIFIER: { - VAR_REF* vref = aCode->createVarRef( this, node->value.str, "" ); + VAR_REF* vref = aCode->CreateVarRef( node->value.str, "" ); - if( m_errorStatus.pendingError ) + if( !vref ) { - m_errorStatus.pendingError = true; - m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN; - - if( m_errorStatus.message == "var" ) - { - m_errorStatus.message.Printf( _( "Unrecognized item '%s'" ), - node->value.str ); - m_errorStatus.srcPos = node->srcPos - strlen( node->value.str ); - } - + msg.Printf( _( "Unrecognized item '%s'" ), node->value.str ); + reportError( msg, node->leaf[0]->srcPos - (int) strlen( node->value.str ) ); return false; } diff --git a/include/libeval_compiler/libeval_compiler.h b/include/libeval_compiler/libeval_compiler.h index cdf20949eb..c99008b94d 100644 --- a/include/libeval_compiler/libeval_compiler.h +++ b/include/libeval_compiler/libeval_compiler.h @@ -77,7 +77,8 @@ enum VAR_TYPE_T { VT_STRING = 1, VT_NUMERIC, - VT_UNDEFINED + VT_UNDEFINED, + VT_PARSE_ERROR }; enum TOKEN_TYPE_T @@ -287,13 +288,13 @@ public: return m_stack.size(); } - ERROR_STATUS GetErrorStatus() const { return m_errorStatus; } - void ReportError( const wxString& aErrorMsg ); + void ReportError( const wxString& aErrorMsg ) { m_errorMessage = aErrorMsg; } + const wxString& GetError() const { return m_errorMessage; } private: std::vector m_ownedValues; std::stack m_stack; - ERROR_STATUS m_errorStatus; + wxString m_errorMessage; }; @@ -312,12 +313,12 @@ public: VALUE* Run( CONTEXT* ctx ); std::string Dump() const; - virtual VAR_REF* createVarRef( COMPILER* aCompiler, const char* var, const char* field ) + virtual VAR_REF* CreateVarRef( const char* var, const char* field ) { return nullptr; }; - virtual FUNC_PTR createFuncCall( COMPILER* aCompiler, const char* name ) + virtual FUNC_PTR CreateFuncCall( const char* name ) { return nullptr; }; @@ -402,7 +403,7 @@ private: class COMPILER { public: - COMPILER(); + COMPILER( REPORTER* aReporter, int aSourceLine, int aSourceOffset ); virtual ~COMPILER(); /* @@ -417,18 +418,10 @@ public: int GetSourcePos() const { return m_sourcePos; } - /* Check if previous invokation of process() was successful */ - inline bool IsValid() const - { - return !m_errorStatus.pendingError; - } - void setRoot( LIBEVAL::TREE_NODE root ); void freeTree( LIBEVAL::TREE_NODE *tree ); bool Compile( const std::string& aString, UCODE* aCode, CONTEXT* aPreflightContext ); - void ReportError( const wxString& aErrorMsg ); - ERROR_STATUS GetErrorStatus() const { return m_errorStatus; } protected: enum LEXER_STATE @@ -441,6 +434,7 @@ protected: bool generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ); + void reportError( const wxString& aErrorMsg, int aPos = -1 ); /* Token type used by the tokenizer */ struct T_TOKEN @@ -483,8 +477,8 @@ protected: return uop; } +protected: /* Token state for input string. */ - void* m_parser; // the current lemon parser state machine TOKENIZER m_tokenizer; char m_localeDecimalSeparator; @@ -492,9 +486,12 @@ protected: std::unique_ptr m_unitResolver; int m_sourcePos; - ERROR_STATUS m_errorStatus; bool m_parseFinished; + REPORTER* m_reporter; + int m_originLine; // Location in the file of the start of the expression + int m_originOffset; + TREE_NODE* m_tree; }; diff --git a/pcbnew/dialogs/panel_setup_rules.cpp b/pcbnew/dialogs/panel_setup_rules.cpp index 7e7d266255..978452b988 100644 --- a/pcbnew/dialogs/panel_setup_rules.cpp +++ b/pcbnew/dialogs/panel_setup_rules.cpp @@ -21,6 +21,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +49,8 @@ PANEL_SETUP_RULES::PANEL_SETUP_RULES( PAGED_DIALOG* aParent, PCB_EDIT_FRAME* aFr for( size_t i = 0; i < wxSTC_STYLE_MAX; ++i ) m_textEditor->StyleSetFont( i, fixedFont ); + m_compileButton->SetBitmap( KiBitmap( reload_xpm ) ); + m_textEditor->Bind( wxEVT_STC_CHARADDED, &PANEL_SETUP_RULES::onScintillaCharAdded, this ); m_textEditor->Bind( wxEVT_STC_AUTOCOMP_CHAR_DELETED, &PANEL_SETUP_RULES::onScintillaCharAdded, this ); } @@ -224,6 +228,49 @@ void PANEL_SETUP_RULES::onScintillaCharAdded( wxStyledTextEvent &aEvent ) } +void PANEL_SETUP_RULES::OnCompile( wxCommandEvent& event ) +{ + m_errorsReport->Clear(); + + try + { + std::vector dummyRules; + + DRC_RULES_PARSER parser( m_frame->GetBoard(), m_textEditor->GetText(), _( "DRC rules" ) ); + + parser.Parse( dummyRules, m_errorsReport ); + } + catch( PARSE_ERROR& pe ) + { + m_Parent->SetError( pe.What(), this, m_textEditor, pe.lineNumber, pe.byteIndex ); + } + + m_errorsReport->Flush(); +} + + +void PANEL_SETUP_RULES::OnErrorLinkClicked( wxHtmlLinkEvent& event ) +{ + wxString link = event.GetLinkInfo().GetHref(); + wxArrayString parts; + int line = 0, offset = 0; + + wxStringSplit( link, parts, ':' ); + + if( parts.size() > 1 ) + { + line = (int) strtol( parts[0], nullptr, 10 ); + offset = (int) strtol( parts[1], nullptr, 10 ); + } + + int pos = m_textEditor->PositionFromLine( line - 1 ) + ( offset - 1 ); + + m_textEditor->GotoPos( pos ); + + m_textEditor->SetFocus(); +} + + bool PANEL_SETUP_RULES::TransferDataToWindow() { wxString rulesFilepath = m_frame->Prj().AbsolutePath( "drc-rules" ); @@ -249,7 +296,7 @@ bool PANEL_SETUP_RULES::TransferDataFromWindow() DRC_RULES_PARSER parser( m_frame->GetBoard(), m_textEditor->GetText(), _( "DRC rules" ) ); - parser.Parse( dummyRules ); + parser.Parse( dummyRules, m_errorsReport ); } catch( PARSE_ERROR& pe ) { diff --git a/pcbnew/dialogs/panel_setup_rules.h b/pcbnew/dialogs/panel_setup_rules.h index 1ac5aa9009..d7b0527013 100644 --- a/pcbnew/dialogs/panel_setup_rules.h +++ b/pcbnew/dialogs/panel_setup_rules.h @@ -49,6 +49,8 @@ private: void onScintillaCharAdded( wxStyledTextEvent &aEvent ); void OnSyntaxHelp( wxHyperlinkEvent& aEvent ) override; + void OnCompile( wxCommandEvent& event ); + void OnErrorLinkClicked( wxHtmlLinkEvent& event ) override; bool TransferDataToWindow() override; bool TransferDataFromWindow() override; diff --git a/pcbnew/dialogs/panel_setup_rules_base.cpp b/pcbnew/dialogs/panel_setup_rules_base.cpp index ac954df880..e32b7a2f61 100644 --- a/pcbnew/dialogs/panel_setup_rules_base.cpp +++ b/pcbnew/dialogs/panel_setup_rules_base.cpp @@ -5,6 +5,8 @@ // PLEASE DO *NOT* EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// +#include "wx_html_report_box.h" + #include "panel_setup_rules_base.h" /////////////////////////////////////////////////////////////////////////// @@ -64,7 +66,21 @@ PANEL_SETUP_RULES_BASE::PANEL_SETUP_RULES_BASE( wxWindow* parent, wxWindowID id, m_textEditor->MarkerDefine( wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_EMPTY ); m_textEditor->SetSelBackground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) ); m_textEditor->SetSelForeground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) ); - m_topMargin->Add( m_textEditor, 1, wxEXPAND | wxALL, 5 ); + m_topMargin->Add( m_textEditor, 3, wxEXPAND | wxALL, 5 ); + + wxBoxSizer* bSizer5; + bSizer5 = new wxBoxSizer( wxHORIZONTAL ); + + m_compileButton = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW|0 ); + bSizer5->Add( m_compileButton, 0, wxALL, 3 ); + + m_errorsReport = new WX_HTML_REPORT_BOX( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO ); + m_errorsReport->SetMinSize( wxSize( 400,60 ) ); + + bSizer5->Add( m_errorsReport, 1, wxALL|wxEXPAND, 5 ); + + + m_topMargin->Add( bSizer5, 1, wxEXPAND, 5 ); m_leftMargin->Add( m_topMargin, 1, wxEXPAND|wxRIGHT|wxLEFT, 10 ); @@ -79,11 +95,15 @@ PANEL_SETUP_RULES_BASE::PANEL_SETUP_RULES_BASE( wxWindow* parent, wxWindowID id, // Connect Events m_syntaxHelp->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( PANEL_SETUP_RULES_BASE::OnSyntaxHelp ), NULL, this ); + m_compileButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_RULES_BASE::OnCompile ), NULL, this ); + m_errorsReport->Connect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( PANEL_SETUP_RULES_BASE::OnErrorLinkClicked ), NULL, this ); } PANEL_SETUP_RULES_BASE::~PANEL_SETUP_RULES_BASE() { // Disconnect Events m_syntaxHelp->Disconnect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( PANEL_SETUP_RULES_BASE::OnSyntaxHelp ), NULL, this ); + m_compileButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_RULES_BASE::OnCompile ), NULL, this ); + m_errorsReport->Disconnect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( PANEL_SETUP_RULES_BASE::OnErrorLinkClicked ), NULL, this ); } diff --git a/pcbnew/dialogs/panel_setup_rules_base.fbp b/pcbnew/dialogs/panel_setup_rules_base.fbp index 902f6e92a7..f7f6404cf3 100644 --- a/pcbnew/dialogs/panel_setup_rules_base.fbp +++ b/pcbnew/dialogs/panel_setup_rules_base.fbp @@ -221,7 +221,7 @@ 5 wxEXPAND | wxALL - 1 + 3 1 1 @@ -284,6 +284,149 @@ + + 5 + wxEXPAND + 1 + + + bSizer5 + wxHORIZONTAL + none + + 3 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + MyButton + + 0 + + 0 + + + 0 + + 1 + m_compileButton + 1 + + + protected + 1 + + + + Resizable + 1 + 40,40 + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnCompile + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 400,60 + 1 + m_errorsReport + 1 + + + protected + 1 + + Resizable + 1 + + wxHW_SCROLLBAR_AUTO + WX_HTML_REPORT_BOX; wx_html_report_box.h; forward_declare + 0 + + + + + OnErrorLinkClicked + + + + diff --git a/pcbnew/dialogs/panel_setup_rules_base.h b/pcbnew/dialogs/panel_setup_rules_base.h index 52410facba..8f143f14fe 100644 --- a/pcbnew/dialogs/panel_setup_rules_base.h +++ b/pcbnew/dialogs/panel_setup_rules_base.h @@ -10,6 +10,8 @@ #include #include #include +class WX_HTML_REPORT_BOX; + #include #include #include @@ -19,6 +21,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include /////////////////////////////////////////////////////////////////////////// @@ -38,9 +46,13 @@ class PANEL_SETUP_RULES_BASE : public wxPanel wxStaticText* m_title; wxHyperlinkCtrl* m_syntaxHelp; wxStyledTextCtrl* m_textEditor; + wxBitmapButton* m_compileButton; + WX_HTML_REPORT_BOX* m_errorsReport; // Virtual event handlers, overide them in your derived class virtual void OnSyntaxHelp( wxHyperlinkEvent& event ) { event.Skip(); } + virtual void OnCompile( wxCommandEvent& event ) { event.Skip(); } + virtual void OnErrorLinkClicked( wxHtmlLinkEvent& event ) { event.Skip(); } public: diff --git a/pcbnew/drc/drc.cpp b/pcbnew/drc/drc.cpp index 42da492440..703ce12426 100644 --- a/pcbnew/drc/drc.cpp +++ b/pcbnew/drc/drc.cpp @@ -60,7 +60,7 @@ #include #include #include - +#include DRC::DRC() : PCB_TOOL_BASE( "pcbnew.DRCTool" ), @@ -196,7 +196,7 @@ bool DRC::LoadRules() try { DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); - parser.Parse( m_rules ); + parser.Parse( m_rules, &NULL_REPORTER::GetInstance() ); } catch( PARSE_ERROR& pe ) { diff --git a/pcbnew/drc/drc_rule.cpp b/pcbnew/drc/drc_rule.cpp index 05a1117663..f9ec4614fb 100644 --- a/pcbnew/drc/drc_rule.cpp +++ b/pcbnew/drc/drc_rule.cpp @@ -29,53 +29,6 @@ #include -/* - * Rule tokens: - * disallow - * constraint - * condition - * - * Disallow types: - * track - * via - * micro_via - * blind_via - * pad - * zone - * text - * graphic - * hole - * - * Constraint types: - * clearance - * annulus_width - * track_width - * hole - * - * - * (rule "HV" - * (constraint clearance (min 200)) - * (condition "A.Netclass == 'HV' || B.Netclass == 'HV'") - * ) - * - * (rule "HV_external" - * (constraint clearance (min 400)) - * (condition "(A.Netclass == 'HV' && (A.onLayer('F.Cu') || A.onLayer('B.Cu')) - * || (B.Netclass == 'HV' && (B.onLayer('F.Cu') || B.onLayer('B.Cu'))") - * ) - * - * (rule "HV2HV" (constraint clearance (min 200))) - * (rule "HV2HV_external" (constraint clearance (min 500))) - * (rule "pad2padHV" (constraint clearance (min 500))) - * - * (rule "signal" (constraint clearance (min 20))) - * (rule "neckdown" (constraint clearance (min 15))) - * - * (rule "disallowMicrovias" (disallow micro_via)) - * - * - */ - DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint ) { BOARD* board = aItem->GetBoard(); @@ -131,9 +84,9 @@ bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM } -bool DRC_RULE_CONDITION::Compile() +bool DRC_RULE_CONDITION::Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset ) { - PCB_EXPR_COMPILER compiler; + PCB_EXPR_COMPILER compiler( aReporter, aSourceLine, aSourceOffset ); if (!m_ucode) m_ucode = new PCB_EXPR_UCODE; @@ -145,13 +98,7 @@ bool DRC_RULE_CONDITION::Compile() if( ok ) return true; - m_compileError = compiler.GetErrorStatus(); - return false; } -LIBEVAL::ERROR_STATUS DRC_RULE_CONDITION::GetCompilationError() -{ - return m_compileError; -} diff --git a/pcbnew/drc/drc_rule.h b/pcbnew/drc/drc_rule.h index 862cace343..9f7e7da340 100644 --- a/pcbnew/drc/drc_rule.h +++ b/pcbnew/drc/drc_rule.h @@ -85,8 +85,7 @@ public: ~DRC_RULE_CONDITION(); bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB ); - bool Compile(); - LIBEVAL::ERROR_STATUS GetCompilationError(); + bool Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset ); public: LSET m_LayerCondition; @@ -94,7 +93,6 @@ public: wxString m_TargetRuleName; private: - LIBEVAL::ERROR_STATUS m_compileError; PCB_EXPR_UCODE* m_ucode; }; diff --git a/pcbnew/drc/drc_rule_parser.cpp b/pcbnew/drc/drc_rule_parser.cpp index b15d535784..c96ffe0225 100644 --- a/pcbnew/drc/drc_rule_parser.cpp +++ b/pcbnew/drc/drc_rule_parser.cpp @@ -23,11 +23,13 @@ #include -#include -#include #include #include + +#include +#include #include +#include using namespace DRCRULE_T; @@ -37,7 +39,8 @@ DRC_RULES_PARSER::DRC_RULES_PARSER( BOARD* aBoard, const wxString& aSource, DRC_RULES_LEXER( aSource.ToStdString(), aSourceDescr ), m_board( aBoard ), m_requiredVersion( 0 ), - m_tooRecent( false ) + m_tooRecent( false ), + m_reporter( nullptr ) { } @@ -46,33 +49,95 @@ DRC_RULES_PARSER::DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString& DRC_RULES_LEXER( aFile, aFilename ), m_board( aBoard ), m_requiredVersion( 0 ), - m_tooRecent( false ) + m_tooRecent( false ), + m_reporter( nullptr ) { } -void DRC_RULES_PARSER::Parse( std::vector& aRules ) +void DRC_RULES_PARSER::reportError( const wxString& aMessage ) { - bool haveVersion = false; + wxString rest; + wxString first = aMessage.BeforeFirst( '|', &rest ); + wxString msg = wxString::Format( _( "ERROR: %s%s" ), + CurLineNumber(), + CurOffset(), + first, + rest ); + + m_reporter->Report( msg, RPT_SEVERITY_ERROR ); +} + + +void DRC_RULES_PARSER::parseUnknown() +{ + int depth = 1; + + for( T token = NextTok(); token != T_EOF; token = NextTok() ) + { + if( token == T_LEFT ) + depth++; + + if( token == T_RIGHT ) + { + if( --depth == 0 ) + break; + } + } +} + + +void DRC_RULES_PARSER::Parse( std::vector& aRules, REPORTER* aReporter ) +{ + bool haveVersion = false; + wxString msg; + + m_reporter = aReporter; for( T token = NextTok(); token != T_EOF; token = NextTok() ) { if( token != T_LEFT ) - Expecting( T_LEFT ); + reportError( _( "Missing '('." ) ); token = NextTok(); if( !haveVersion && token != T_version ) - Expecting( "version" ); + { + reportError( _( "Missing version statement." ) ); + haveVersion = true; // don't keep on reporting it + } switch( token ) { case T_version: - NeedNUMBER( "version" ); - m_requiredVersion = (int)strtol( CurText(), NULL, 10 ); - m_tooRecent = ( m_requiredVersion > DRC_RULE_FILE_VERSION ); haveVersion = true; - NeedRIGHT(); + token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing version number." ) ); + break; + } + + if( (int) token == DSN_NUMBER ) + { + m_requiredVersion = (int)strtol( CurText(), NULL, 10 ); + m_tooRecent = ( m_requiredVersion > DRC_RULE_FILE_VERSION ); + token = NextTok(); + } + else + { + msg.Printf( _( "Unrecognized item '%s'.| Expected version number" ), FromUTF8() ); + reportError( msg ); + } + + if( (int) token != DSN_RIGHT ) + { + msg.Printf( _( "Unrecognized item '%s'." ), FromUTF8() ); + reportError( msg ); + parseUnknown(); + } + break; case T_rule: @@ -80,9 +145,13 @@ void DRC_RULES_PARSER::Parse( std::vector& aRules ) break; default: - Expecting( "rule" ); + msg.Printf( _( "Unrecognized item '%s'.| Expected 'rule' or 'version'." ), FromUTF8() ); + reportError( msg ); + parseUnknown(); } } + + m_reporter = nullptr; } @@ -90,23 +159,33 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE() { DRC_RULE* rule = new DRC_RULE(); T token = NextTok(); + wxString msg; if( !IsSymbol( token ) ) - Expecting( "rule name" ); + reportError( _( "Missing rule name." ) ); rule->m_Name = FromUTF8(); for( token = NextTok(); token != T_RIGHT; token = NextTok() ) { if( token != T_LEFT ) - Expecting( T_LEFT ); + reportError( _( "Missing '('." ) ); token = NextTok(); switch( token ) { case T_disallow: - switch( NextTok() ) + token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing disallowed type.| Expected 'track', 'via', 'micro_via', " + "'blind_via', 'pad', 'zone', 'text', 'graphic' or 'hole'." ) ); + break; + } + + switch( token ) { case T_track: rule->m_DisallowFlags |= DISALLOW_TRACKS; break; case T_via: rule->m_DisallowFlags |= DISALLOW_VIAS; break; @@ -118,12 +197,21 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE() case T_graphic: rule->m_DisallowFlags |= DISALLOW_GRAPHICS; break; case T_hole: rule->m_DisallowFlags |= DISALLOW_HOLES; break; case T_footprint: rule->m_DisallowFlags |= DISALLOW_FOOTPRINTS; break; - default: Expecting( "track, via, micro_via, blind_via, pad, zone, text, " - "graphic, or hole" ); + default: + msg.Printf( _( "Unrecognized item '%s'.| Expected 'track', 'via', 'micro_via', " + "'blind_via', 'pad', 'zone', 'text', 'graphic' or 'hole'." ), + FromUTF8() ); + reportError( msg ); } rule->m_ConstraintFlags = DISALLOW_CONSTRAINT; - NeedRIGHT(); + + if( (int) NextTok() != DSN_RIGHT ) + { + reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) ); + parseUnknown(); + } + break; case T_constraint: @@ -131,17 +219,32 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE() break; case T_condition: - NeedSYMBOL(); - rule->m_Condition.m_Expression = FromUTF8(); + token = NextTok(); - if( !rule->m_Condition.Compile() ) + if( (int) token == DSN_RIGHT ) { - LIBEVAL::ERROR_STATUS error = rule->m_Condition.GetCompilationError(); - THROW_PARSE_ERROR( error.message, CurSource(), CurLine(), CurLineNumber(), - CurOffset() + error.srcPos ); + reportError( _( "Missing condition expression." ) ); + break; + } + + if( IsSymbol( token ) ) + { + rule->m_Condition.m_Expression = FromUTF8(); + rule->m_Condition.Compile( m_reporter, CurLineNumber(), CurOffset() ); + } + else + { + msg.Printf( _( "Unrecognized item '%s'.| Expected quoted expression." ), + FromUTF8() ); + reportError( msg ); + } + + if( (int) NextTok() != DSN_RIGHT ) + { + reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) ); + parseUnknown(); } - NeedRIGHT(); break; case T_layer: @@ -149,7 +252,11 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE() break; default: - Expecting( "disallow, constraint or condition" ); + msg.Printf( _( "Unrecognized item '%s'.| Expected 'constraint', 'condition' or " + "'disallow'." ), + FromUTF8() ); + reportError( msg ); + parseUnknown(); } } @@ -159,17 +266,31 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE() void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) { - T token; - int constraintType; - int value; + T token; + int constraintType = 0; + int value; + wxString msg; - switch( NextTok() ) + token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing constraint type.| Expected 'clearance', 'track_width', " + "'annulus_width' or 'hole'." ) ); + return; + } + + switch( token ) { case T_clearance: constraintType = CLEARANCE_CONSTRAINT; break; case T_track_width: constraintType = TRACK_CONSTRAINT; break; case T_annulus_width: constraintType = ANNULUS_CONSTRAINT; break; case T_hole: constraintType = HOLE_CONSTRAINT; break; - default: Expecting( "clearance, track_width, annulus_width, or hole" ); return; + default: + msg.Printf( _( "Unrecognized item '%s'.| Expected 'clearance', 'track_width', " + "'annulus_width' or 'hole'." ), + FromUTF8() ); + reportError( msg ); } aRule->m_ConstraintFlags |= constraintType; @@ -177,14 +298,21 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) for( token = NextTok(); token != T_RIGHT; token = NextTok() ) { if( token != T_LEFT ) - Expecting( T_LEFT ); + reportError( _( "Missing '('." ) ); token = NextTok(); switch( token ) { case T_min: - NextTok(); + token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing min value." ) ); + break; + } + parseValueWithUnits( FromUTF8(), value ); switch( constraintType ) @@ -195,39 +323,69 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) case HOLE_CONSTRAINT: aRule->m_MinHole = value; break; } - NeedRIGHT(); + if( (int) NextTok() != DSN_RIGHT ) + { + reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) ); + parseUnknown(); + } + break; case T_max: - NextTok(); + token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing max value." ) ); + break; + } + parseValueWithUnits( FromUTF8(), value ); switch( constraintType ) { case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Max = value; break; case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Max = value; break; - default: Expecting( "min" ); } - NeedRIGHT(); + if( (int) NextTok() != DSN_RIGHT ) + { + reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) ); + parseUnknown(); + } + break; case T_opt: - NextTok(); + token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing opt value." ) ); + break; + } + parseValueWithUnits( FromUTF8(), value ); switch( constraintType ) { case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Opt = value; break; case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Opt = value; break; - default: Expecting( "min" ); } - NeedRIGHT(); + if( (int) NextTok() != DSN_RIGHT ) + { + reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) ); + parseUnknown(); + } + break; default: - Expecting( "allow or constraint" ); + msg.Printf( _( "Unrecognized item '%s'.| Expected 'min', 'max' or 'opt'." ), + FromUTF8() ); + reportError( msg ); + parseUnknown(); } } } @@ -235,17 +393,9 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult ) { - PCB_EXPR_EVALUATOR evaluator; - - bool ok = evaluator.Evaluate( aExpr ); - - if( !ok ) - { - LIBEVAL::ERROR_STATUS error = evaluator.GetErrorStatus(); - THROW_PARSE_ERROR( error.message, CurSource(), CurLine(), CurLineNumber(), - CurOffset() + error.srcPos ); - } + PCB_EXPR_EVALUATOR evaluator( m_reporter, CurLineNumber(), CurOffset() ); + evaluator.Evaluate( aExpr ); aResult = evaluator.Result(); } @@ -253,13 +403,18 @@ void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult LSET DRC_RULES_PARSER::parseLayer() { LSET retVal; - int tok = NextTok(); + int token = NextTok(); - if( tok == T_outer ) + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing layer name or type." ) ); + return LSET::AllCuMask(); + } + else if( token == T_outer ) { retVal = LSET::ExternalCuMask(); } - else if( tok == T_inner ) + else if( token == T_inner ) { retVal = LSET::InternalCuMask(); } @@ -269,14 +424,16 @@ LSET DRC_RULES_PARSER::parseLayer() PCB_LAYER_ID layer = ENUM_MAP::Instance().ToEnum( layerName ); if( layer == UNDEFINED_LAYER ) - { - wxString msg = wxString::Format( _( "Unrecognized layer '%s' " ), layerName ); - THROW_PARSE_ERROR( msg, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); - } + reportError( wxString::Format( _( "Unrecognized layer '%s' " ), layerName ) ); retVal.set( layer ); } - NeedRIGHT(); + if( (int) NextTok() != DSN_RIGHT ) + { + reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) ); + parseUnknown(); + } + return retVal; } diff --git a/pcbnew/drc/drc_rule_parser.h b/pcbnew/drc/drc_rule_parser.h index 404188bac4..5e7dac54f7 100644 --- a/pcbnew/drc/drc_rule_parser.h +++ b/pcbnew/drc/drc_rule_parser.h @@ -43,7 +43,7 @@ public: DRC_RULES_PARSER( BOARD* aBoard, const wxString& aSource, const wxString& aSourceDescr ); DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString& aFilename ); - void Parse( std::vector& aRules ); + void Parse( std::vector& aRules, REPORTER* aReporter ); private: DRC_RULE* parseDRC_RULE(); @@ -51,11 +51,15 @@ private: void parseConstraint( DRC_RULE* aRule ); void parseValueWithUnits( const wxString& aExpr, int& aResult ); LSET parseLayer(); + void parseUnknown(); + + void reportError( const wxString& aMessage ); private: - BOARD* m_board; - int m_requiredVersion; - bool m_tooRecent; + BOARD* m_board; + int m_requiredVersion; + bool m_tooRecent; + REPORTER* m_reporter; }; #endif // DRC_RULE_PARSER_H diff --git a/pcbnew/pcb_expr_evaluator.cpp b/pcbnew/pcb_expr_evaluator.cpp index b99cf1ffbe..8224cf2f88 100644 --- a/pcbnew/pcb_expr_evaluator.cpp +++ b/pcbnew/pcb_expr_evaluator.cpp @@ -25,9 +25,9 @@ #include #include #include -#include "class_board.h" -#include "pcb_expr_evaluator.h" - +#include +#include +#include static void onLayer( LIBEVAL::CONTEXT* aCtx, void *self ) @@ -187,8 +187,7 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx ) } -LIBEVAL::UCODE::FUNC_PTR PCB_EXPR_UCODE::createFuncCall( LIBEVAL::COMPILER* aCompiler, - const char* aName ) +LIBEVAL::UCODE::FUNC_PTR PCB_EXPR_UCODE::CreateFuncCall( const char* aName ) { PCB_EXPR_BUILTIN_FUNCTIONS& registry = PCB_EXPR_BUILTIN_FUNCTIONS::Instance(); @@ -199,8 +198,7 @@ LIBEVAL::UCODE::FUNC_PTR PCB_EXPR_UCODE::createFuncCall( LIBEVAL::COMPILER* aCom } -LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, const char* aVar, - const char* aField ) +LIBEVAL::VAR_REF* PCB_EXPR_UCODE::CreateVarRef( const char* aVar, const char* aField ) { PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); PCB_EXPR_VAR_REF* vref = nullptr; @@ -215,7 +213,6 @@ LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, co } else { - aCompiler->ReportError( "var" ); return vref; } @@ -251,16 +248,14 @@ LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, co } else { - (void) 0; // should we do anything here? - //msg.Printf("Unrecognized type for property '%s'", field.c_str() ); - //aCompiler->ReportError( (const char*) msg.c_str() ); + wxFAIL_MSG( "PCB_EXPR_UCODE::createVarRef: Unknown property type." ); } } } } if( vref->GetType() == LIBEVAL::VT_UNDEFINED ) - aCompiler->ReportError( "field" ); + vref->SetType( LIBEVAL::VT_PARSE_ERROR ); return vref; } @@ -295,13 +290,15 @@ public: }; -PCB_EXPR_COMPILER::PCB_EXPR_COMPILER() +PCB_EXPR_COMPILER::PCB_EXPR_COMPILER( REPORTER* aReporter, int aSourceLine, int aSourcePos ) : + COMPILER( aReporter, aSourceLine, aSourcePos ) { m_unitResolver = std::make_unique(); } -PCB_EXPR_EVALUATOR::PCB_EXPR_EVALUATOR() +PCB_EXPR_EVALUATOR::PCB_EXPR_EVALUATOR( REPORTER* aReporter, int aSourceLine, int aSourceOffset ) : + m_compiler( aReporter, aSourceLine, aSourceOffset ) { m_result = 0; } @@ -316,15 +313,10 @@ bool PCB_EXPR_EVALUATOR::Evaluate( const wxString& aExpr ) PCB_EXPR_UCODE ucode; LIBEVAL::CONTEXT preflightContext; - if( !m_compiler.Compile( aExpr.ToUTF8().data(), &ucode, &preflightContext ) ) - { - m_errorStatus = m_compiler.GetErrorStatus(); - return false; - } + m_compiler.Compile( aExpr.ToUTF8().data(), &ucode, &preflightContext ); -// fixme: handle error conditions - LIBEVAL::CONTEXT ctx; - LIBEVAL::VALUE* result = ucode.Run( &ctx ); + LIBEVAL::CONTEXT evaluationContext; + LIBEVAL::VALUE* result = ucode.Run( &evaluationContext ); if( result->GetType() == LIBEVAL::VT_NUMERIC ) m_result = KiROUND( result->AsDouble() ); diff --git a/pcbnew/pcb_expr_evaluator.h b/pcbnew/pcb_expr_evaluator.h index dd3058a627..b1674437c7 100644 --- a/pcbnew/pcb_expr_evaluator.h +++ b/pcbnew/pcb_expr_evaluator.h @@ -43,10 +43,9 @@ public: PCB_EXPR_UCODE() {}; virtual ~PCB_EXPR_UCODE() {}; - virtual LIBEVAL::VAR_REF* createVarRef( LIBEVAL::COMPILER *aCompiler, const char* aVar, - const char* aField ) override; + virtual LIBEVAL::VAR_REF* CreateVarRef( const char* aVar, const char* aField ) override; - virtual FUNC_PTR createFuncCall( LIBEVAL::COMPILER* aCompiler, const char* aName ) override; + virtual FUNC_PTR CreateFuncCall( const char* aName ) override; }; @@ -83,7 +82,7 @@ public: m_type( LIBEVAL::VT_UNDEFINED ), m_isEnum( false ) { - //printf("*** createVarRef %p %d\n", this, aItemIndex ); + //printf("*** CreateVarRef %p %d\n", this, aItemIndex ); } void SetIsEnum( bool s ) { m_isEnum = s; } @@ -142,28 +141,24 @@ private: class PCB_EXPR_COMPILER : public LIBEVAL::COMPILER { public: - PCB_EXPR_COMPILER(); + PCB_EXPR_COMPILER( REPORTER* aReporter, int aSourceLine, int aSourcePos ); }; class PCB_EXPR_EVALUATOR { public: - PCB_EXPR_EVALUATOR(); + PCB_EXPR_EVALUATOR( REPORTER* aReporter, int aSourceLine, int aSourceOffset ); ~PCB_EXPR_EVALUATOR(); bool Evaluate( const wxString& aExpr ); int Result() const { return m_result; } - LIBEVAL::ERROR_STATUS GetErrorStatus() { return m_errorStatus; } - private: int m_result; PCB_EXPR_COMPILER m_compiler; PCB_EXPR_UCODE m_ucode; - - LIBEVAL::ERROR_STATUS m_errorStatus; }; #endif diff --git a/qa/drc_proto/drc_engine.cpp b/qa/drc_proto/drc_engine.cpp index f670a5b4f7..4391db88a1 100644 --- a/qa/drc_proto/drc_engine.cpp +++ b/qa/drc_proto/drc_engine.cpp @@ -78,7 +78,7 @@ bool test::DRC_ENGINE::LoadRules( wxFileName aPath ) try { DRC_RULES_PARSER parser( m_board, fp, aPath.GetFullPath() ); - parser.Parse( m_ruleConditions, m_rules ); + parser.Parse( m_ruleConditions, m_rules, &NULL_REPORTER::GetInstance() ); } catch( PARSE_ERROR& pe ) { @@ -88,7 +88,7 @@ bool test::DRC_ENGINE::LoadRules( wxFileName aPath ) //wxSafeYield( m_editFrame ); //m_editFrame->ShowBoardSetupDialog( _( "Rules" ), pe.What(), ID_RULES_EDITOR, - // pe.lineNumber, pe.byteIndex ); + // pe.lineNumber, pe.byteIndex ); throw; @@ -175,7 +175,7 @@ bool test::DRC_ENGINE::CompileRules() { rcons->conditions.push_back( condition ); - bool compileOk = condition->Compile(); + bool compileOk = condition->Compile( &NULL_REPORTER::GetInstance() ); ReportAux( wxString::Format( " |- condition: '%s' compile: %s", condition->m_TargetRuleName, compileOk ? "OK" : "ERROR") ); diff --git a/qa/drc_proto/drc_rule.cpp b/qa/drc_proto/drc_rule.cpp index 0c21240f49..0318bf120a 100644 --- a/qa/drc_proto/drc_rule.cpp +++ b/qa/drc_proto/drc_rule.cpp @@ -64,9 +64,9 @@ bool test::DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOAR } -bool test::DRC_RULE_CONDITION::Compile() +bool test::DRC_RULE_CONDITION::Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset ) { - PCB_EXPR_COMPILER compiler; + PCB_EXPR_COMPILER compiler( aReporter, aSourceLine, aSourceOffset ); if (!m_ucode) m_ucode = new PCB_EXPR_UCODE; @@ -74,19 +74,7 @@ bool test::DRC_RULE_CONDITION::Compile() LIBEVAL::CONTEXT preflightContext; bool ok = compiler.Compile( m_Expression.ToUTF8().data(), m_ucode, &preflightContext ); - - if( ok ) - return true; - - m_compileError = compiler.GetErrorStatus(); - - printf( "Fail: %s (pos: %d)\n", (const char *) m_compileError.message.c_str(), m_compileError.srcPos ); - - return false; + return ok; } -LIBEVAL::ERROR_STATUS test::DRC_RULE_CONDITION::GetCompilationError() -{ - return m_compileError; -} diff --git a/qa/drc_proto/drc_rule.h b/qa/drc_proto/drc_rule.h index d9333efb1c..6df2e3097f 100644 --- a/qa/drc_proto/drc_rule.h +++ b/qa/drc_proto/drc_rule.h @@ -125,6 +125,7 @@ public: DRC_CONSTRAINT m_Constraint; }; + class DRC_RULE_CONDITION { public: @@ -132,15 +133,14 @@ public: ~DRC_RULE_CONDITION(); bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB ); - bool Compile(); - LIBEVAL::ERROR_STATUS GetCompilationError(); + bool Compile( REPORTER* aReporter, int aSourceLine = 0, int aSourceOffset = 0 ); public: + LSET m_LayerCondition; wxString m_Expression; wxString m_TargetRuleName; private: - LIBEVAL::ERROR_STATUS m_compileError; PCB_EXPR_UCODE* m_ucode; }; diff --git a/qa/drc_proto/drc_rule_parser.cpp b/qa/drc_proto/drc_rule_parser.cpp index ecb5b1a13e..8f828afc9d 100644 --- a/qa/drc_proto/drc_rule_parser.cpp +++ b/qa/drc_proto/drc_rule_parser.cpp @@ -22,6 +22,7 @@ */ +#include #include #include @@ -29,11 +30,8 @@ #include #include #include // drc_dbg - - -#include - #include +#include using namespace DRCRULEPROTO_T; @@ -43,37 +41,94 @@ test::DRC_RULES_PARSER::DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxSt m_requiredVersion( 0 ), m_tooRecent( false ) { - for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer ) +} + + +void test::DRC_RULES_PARSER::reportError( const wxString& aMessage ) +{ + wxString rest; + wxString first = aMessage.BeforeFirst( '|', &rest ); + wxString msg = wxString::Format( _( "ERROR: %s%s" ), + CurLineNumber(), + CurOffset(), + first, + rest ); + + m_reporter->Report( msg, RPT_SEVERITY_ERROR ); +} + + +void test::DRC_RULES_PARSER::parseUnknown() +{ + int depth = 1; + + for( T token = NextTok(); token != T_EOF; token = NextTok() ) { - std::string untranslated = TO_UTF8( wxString( LSET::Name( PCB_LAYER_ID( layer ) ) ) ); - m_layerMap[untranslated] = PCB_LAYER_ID( layer ); + if( token == T_LEFT ) + depth++; + + if( token == T_RIGHT ) + { + if( --depth == 0 ) + break; + } } } -void test::DRC_RULES_PARSER::Parse( - std::vector& aConditions, std::vector& aRules ) +void test::DRC_RULES_PARSER::Parse( std::vector& aConditions, + std::vector& aRules, + REPORTER* aReporter ) { - bool haveVersion = false; + bool haveVersion = false; + wxString msg; + + m_reporter = aReporter; for( T token = NextTok(); token != T_EOF; token = NextTok() ) { if( token != T_LEFT ) - Expecting( T_LEFT ); + reportError( _( "Missing '('." ) ); token = NextTok(); if( !haveVersion && token != T_version ) - Expecting( "version" ); + { + reportError( _( "Missing version statement." ) ); + haveVersion = true; // don't keep on reporting it + } switch( token ) { case T_version: - NeedNUMBER( "version" ); - m_requiredVersion = (int) strtol( CurText(), NULL, 10 ); - m_tooRecent = ( m_requiredVersion > DRC_RULE_FILE_VERSION ); - haveVersion = true; - NeedRIGHT(); + haveVersion = true; + token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing version number." ) ); + break; + } + + if( (int) token == DSN_NUMBER ) + { + m_requiredVersion = (int)strtol( CurText(), NULL, 10 ); + m_tooRecent = ( m_requiredVersion > DRC_RULE_FILE_VERSION ); + token = NextTok(); + } + else + { + msg.Printf( _( "Unrecognized item '%s'.| Expected version number" ), FromUTF8() ); + reportError( msg ); + } + + if( (int) token != DSN_RIGHT ) + { + msg.Printf( _( "Unrecognized item '%s'." ), FromUTF8() ); + reportError( msg ); + parseUnknown(); + } + break; case T_condition: @@ -89,7 +144,10 @@ void test::DRC_RULES_PARSER::Parse( } default: - Expecting( "condition or rule" ); + msg.Printf( _( "Unrecognized item '%s'.| Expected 'rule', 'condition' or 'version'." ), + FromUTF8() ); + reportError( msg ); + parseUnknown(); } } } @@ -109,6 +167,8 @@ test::DRC_RULE_CONDITION* test::DRC_RULES_PARSER::parseCONDITION() //printf( "Do token xxx %d '%s'\n", token, (const char*) FromUTF8().c_str() ); + // TODO: Needs updating to report errors through REPORTER + switch( token ) { case T_expression: @@ -139,16 +199,17 @@ test::DRC_RULE* test::DRC_RULES_PARSER::parseRULE() DRC_RULE* rule = new DRC_RULE(); T token = NextTok(); int value; + wxString msg; if( !IsSymbol( token ) ) - Expecting( "rule name" ); + reportError( _( "Missing rule name." ) ); rule->m_Name = FromUTF8(); for( token = NextTok(); token != T_RIGHT; token = NextTok() ) { if( token != T_LEFT ) - Expecting( T_LEFT ); + reportError( _( "Missing '('." ) ); token = NextTok(); @@ -157,26 +218,70 @@ test::DRC_RULE* test::DRC_RULES_PARSER::parseRULE() switch( token ) { case T_type: + // TODO: I assume this won't be in the final impl and so doesn't need converting + // to new error reporting framework? NeedSYMBOL(); rule->m_TestProviderName = FromUTF8(); break; case T_min: - NeedSYMBOL(); + token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing min value." ) ); + break; + } + parseValueWithUnits( FromUTF8(), value ); rule->m_Constraint.m_Value.SetMin( value ); + + if( (int) NextTok() != DSN_RIGHT ) + { + reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) ); + parseUnknown(); + } + break; case T_opt: - NeedSYMBOL(); + token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing opt value." ) ); + break; + } + parseValueWithUnits( FromUTF8(), value ); rule->m_Constraint.m_Value.SetOpt( value ); + + if( (int) NextTok() != DSN_RIGHT ) + { + reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) ); + parseUnknown(); + } + break; case T_max: - NeedSYMBOL(); + token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing max value." ) ); + break; + } + parseValueWithUnits( FromUTF8(), value ); rule->m_Constraint.m_Value.SetMax( value ); + + if( (int) NextTok() != DSN_RIGHT ) + { + reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) ); + parseUnknown(); + } + break; case T_allow: @@ -209,7 +314,12 @@ test::DRC_RULE* test::DRC_RULES_PARSER::parseRULE() default: - Expecting( "type, min, opt, max, allow, enable, priority or severity" ); + // TODO: reconcile + //Expecting( "type, min, opt, max, allow, enable, priority or severity" ); + msg.Printf( _( "Unrecognized item '%s'.| Expected 'min', 'max' or 'opt'." ), + FromUTF8() ); + reportError( msg ); + parseUnknown(); break; } @@ -222,16 +332,47 @@ test::DRC_RULE* test::DRC_RULES_PARSER::parseRULE() void test::DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult ) { - PCB_EXPR_EVALUATOR evaluator; - - bool ok = evaluator.Evaluate( aExpr ); - - if( !ok ) - { - LIBEVAL::ERROR_STATUS error = evaluator.GetErrorStatus(); - THROW_PARSE_ERROR( error.message, CurSource(), CurLine(), CurLineNumber(), - CurOffset() + error.srcPos ); - } + PCB_EXPR_EVALUATOR evaluator( m_reporter, CurLineNumber(), CurOffset() ); + evaluator.Evaluate( aExpr ); aResult = evaluator.Result(); }; + + +LSET test::DRC_RULES_PARSER::parseLayer() +{ + LSET retVal; + int token = NextTok(); + + if( (int) token == DSN_RIGHT ) + { + reportError( _( "Missing layer name or type." ) ); + return LSET::AllCuMask(); + } + else if( token == T_outer ) + { + retVal = LSET::ExternalCuMask(); + } + else if( token == T_inner ) + { + retVal = LSET::InternalCuMask(); + } + else + { + wxString layerName = FromUTF8(); + PCB_LAYER_ID layer = ENUM_MAP::Instance().ToEnum( layerName ); + + if( layer == UNDEFINED_LAYER ) + reportError( wxString::Format( _( "Unrecognized layer '%s' " ), layerName ) ); + + retVal.set( layer ); + } + + if( (int) NextTok() != DSN_RIGHT ) + { + reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) ); + parseUnknown(); + } + + return retVal; +} diff --git a/qa/drc_proto/drc_rule_parser.h b/qa/drc_proto/drc_rule_parser.h index c45f6afd87..fbcb2657a0 100644 --- a/qa/drc_proto/drc_rule_parser.h +++ b/qa/drc_proto/drc_rule_parser.h @@ -45,7 +45,8 @@ class DRC_RULES_PARSER : public DRC_RULES_PROTO_LEXER public: DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString& aFilename ); - void Parse( std::vector& aConditions, std::vector& aRules ); + void Parse( std::vector& aConditions, std::vector& aRules, + REPORTER* aReporter ); private: DRC_RULE_CONDITION* parseCONDITION(); @@ -63,16 +64,20 @@ private: return parseInt(); } -// void parseConstraint( DRC_RULE* aRule ); + LSET parseLayer(); + void parseUnknown(); + + void reportError( const wxString& aMessage ); + + // void parseConstraint( DRC_RULE* aRule ); //int parseValue( DRCRULE_T::T aToken ); private: - BOARD* m_board; - int m_requiredVersion; - bool m_tooRecent; - - std::unordered_map m_layerMap; + BOARD* m_board; + int m_requiredVersion; + bool m_tooRecent; + REPORTER* m_reporter; }; }; diff --git a/qa/drc_proto/drc_rules_proto.keywords b/qa/drc_proto/drc_rules_proto.keywords index 8075c026c1..3d672a8fab 100644 --- a/qa/drc_proto/drc_rules_proto.keywords +++ b/qa/drc_proto/drc_rules_proto.keywords @@ -1,11 +1,16 @@ +clearance condition +constraint +inner +layer max min +name opt +outer allow rule version -name priority expression enable