From 095937563b0778b58852d881e214909810808abe Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sun, 19 Jul 2020 22:22:49 +0100 Subject: [PATCH] Hook libeval compiler up to rule parser - convert expression string tokens to single-quote-delimited - fix bug where netclass assignments weren't getting updated after board setup dialog - move property manager rebuild to lazy evaluation - improve performance with wider use of const& - retire DRC_SELECTOR stuff - use wxString for GUI stuff (particularly translated stuff) - fix EqualTo() to return false instead of asserting when op types don't match - fix buffer overruns with fixed-size string buffers - make expression function calls case-insensitive - integrate expression errors into rule parser - produce more and better error messages - keep BOARD_ITEM ptrs const as long as possible - fix a couple of uninitialized variables --- common/libeval_compiler/grammar.c | 38 +-- common/libeval_compiler/grammar.lemon | 42 +-- common/libeval_compiler/libeval_compiler.cpp | 215 ++++++------ common/project/net_settings.cpp | 19 +- common/property_mgr.cpp | 50 +-- eeschema/eeschema_config.cpp | 2 +- include/board_design_settings.h | 15 +- include/class_board_item.h | 45 +++ include/libeval_compiler/libeval_compiler.h | 307 +++++++++--------- include/project/net_settings.h | 5 +- include/property.h | 13 +- pcbnew/board_connected_item.cpp | 6 +- pcbnew/board_design_settings.cpp | 2 - pcbnew/class_board.cpp | 46 --- pcbnew/class_board_item.cpp | 17 +- pcbnew/class_module.cpp | 4 +- pcbnew/class_module.h | 7 +- .../dialogs/panel_pcbnew_color_settings.cpp | 3 +- pcbnew/dialogs/panel_pcbnew_color_settings.h | 2 - pcbnew/dialogs/panel_setup_rules.cpp | 9 +- pcbnew/drc/drc.cpp | 7 +- pcbnew/drc/drc.h | 1 - pcbnew/drc/drc_rule.cpp | 155 +++++---- pcbnew/drc/drc_rule.h | 70 ++-- pcbnew/drc/drc_rule_parser.cpp | 135 +------- pcbnew/drc/drc_rule_parser.h | 4 +- pcbnew/pcb_edit_frame.cpp | 2 +- pcbnew/pcb_expr_evaluator.cpp | 179 +++++----- pcbnew/pcb_expr_evaluator.h | 10 +- qa/drc_proto/drc.cpp | 4 +- qa/drc_proto/drc_rule.cpp | 14 +- qa/drc_proto/drc_rule.h | 4 +- qa/libeval_compiler/libeval_compiler_test.cpp | 18 +- 33 files changed, 708 insertions(+), 742 deletions(-) diff --git a/common/libeval_compiler/grammar.c b/common/libeval_compiler/grammar.c index ed5c46e052..8f770693cb 100644 --- a/common/libeval_compiler/grammar.c +++ b/common/libeval_compiler/grammar.c @@ -971,114 +971,114 @@ static YYACTIONTYPE yy_reduce( break; case 1: /* expr ::= G_VALUE */ #line 58 "grammar.lemon" -{ yylhsminor.yy0.op = TR_NUMBER; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; } +{ yylhsminor.yy0.op = TR_NUMBER; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 976 "grammar.c" yymsp[0].minor.yy0 = yylhsminor.yy0; break; case 2: /* expr ::= G_VALUE G_UNIT */ #line 59 "grammar.lemon" -{ yylhsminor.yy0.op = TR_NUMBER; yylhsminor.yy0.value = yymsp[-1].minor.yy0.value; yylhsminor.yy0.leaf[0] = newNode( TR_UNIT, yymsp[0].minor.yy0.value.type, ""); yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; } +{ yylhsminor.yy0.op = TR_NUMBER; yylhsminor.yy0.value = yymsp[-1].minor.yy0.value; yylhsminor.yy0.leaf[0] = newNode( TR_UNIT, yymsp[0].minor.yy0.value.type, ""); yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 982 "grammar.c" yymsp[-1].minor.yy0 = yylhsminor.yy0; break; case 3: /* expr ::= G_STRING */ #line 60 "grammar.lemon" -{ yylhsminor.yy0.op = TR_STRING; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; } +{ yylhsminor.yy0.op = TR_STRING; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 988 "grammar.c" yymsp[0].minor.yy0 = yylhsminor.yy0; break; case 4: /* expr ::= G_IDENTIFIER */ #line 61 "grammar.lemon" -{ yylhsminor.yy0.op = TR_IDENTIFIER; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; } +{ yylhsminor.yy0.op = TR_IDENTIFIER; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 994 "grammar.c" yymsp[0].minor.yy0 = yylhsminor.yy0; break; case 5: /* expr ::= expr G_LESS_THAN expr */ #line 62 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_LESS; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_LESS; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1000 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 6: /* expr ::= expr G_GREATER_THAN expr */ #line 63 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_GREATER; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_GREATER; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1006 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 7: /* expr ::= expr G_LESS_EQUAL_THAN expr */ #line 64 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_LESS_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_LESS_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1012 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 8: /* expr ::= expr G_GREATER_EQUAL_THAN expr */ #line 65 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_GREATER_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_GREATER_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1018 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 9: /* expr ::= expr G_NOT_EQUAL expr */ #line 66 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_NOT_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_NOT_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1024 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 10: /* expr ::= expr G_BOOL_AND expr */ #line 67 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_BOOL_AND; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_BOOL_AND; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1030 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 11: /* expr ::= expr G_BOOL_OR expr */ #line 68 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_BOOL_OR; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_BOOL_OR; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1036 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 12: /* expr ::= expr G_PLUS expr */ #line 69 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_ADD; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_ADD; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1042 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 13: /* expr ::= expr G_MINUS expr */ #line 70 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_SUB; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_SUB; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1048 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 14: /* expr ::= expr G_MULT expr */ #line 71 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_MUL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_MUL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1054 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 15: /* expr ::= expr G_DIVIDE expr */ #line 72 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_DIV; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_DIV; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1060 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 16: /* expr ::= expr G_EQUAL expr */ #line 73 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_OP_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1066 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 17: /* expr ::= expr G_STRUCT_REF expr */ #line 75 "grammar.lemon" -{ yylhsminor.yy0.op = TR_STRUCT_REF; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; } +{ yylhsminor.yy0.op = TR_STRUCT_REF; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1072 "grammar.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 18: /* expr ::= G_PARENL expr G_PARENR */ #line 77 "grammar.lemon" -{ yymsp[-2].minor.yy0.op = yymsp[-1].minor.yy0.op; yymsp[-2].minor.yy0.value = yymsp[-1].minor.yy0.value; yymsp[-2].minor.yy0.valid=yymsp[-1].minor.yy0.valid; yymsp[-2].minor.yy0.leaf[0] = yymsp[-1].minor.yy0.leaf[0]; yymsp[-2].minor.yy0.leaf[1] = yymsp[-1].minor.yy0.leaf[1]; } +{ yymsp[-2].minor.yy0.op = yymsp[-1].minor.yy0.op; yymsp[-2].minor.yy0.value = yymsp[-1].minor.yy0.value; yymsp[-2].minor.yy0.valid=yymsp[-1].minor.yy0.valid; yymsp[-2].minor.yy0.leaf[0] = yymsp[-1].minor.yy0.leaf[0]; yymsp[-2].minor.yy0.leaf[1] = yymsp[-1].minor.yy0.leaf[1]; yymsp[-2].minor.yy0.srcPos = pEval->GetSourcePos(); } #line 1078 "grammar.c" break; case 19: /* expr ::= G_IDENTIFIER G_PARENL expr G_PARENR */ #line 78 "grammar.lemon" -{ yylhsminor.yy0.op = TR_OP_FUNC_CALL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-3].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[-1].minor.yy0); yylhsminor.yy0.valid=1; } +{ yylhsminor.yy0.op = TR_OP_FUNC_CALL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-3].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[-1].minor.yy0); yylhsminor.yy0.valid=1; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); } #line 1083 "grammar.c" yymsp[-3].minor.yy0 = yylhsminor.yy0; break; diff --git a/common/libeval_compiler/grammar.lemon b/common/libeval_compiler/grammar.lemon index bd68af47c3..8ba07802f8 100644 --- a/common/libeval_compiler/grammar.lemon +++ b/common/libeval_compiler/grammar.lemon @@ -53,27 +53,27 @@ in ::= in stmt. /* A statement can be empty, an expr or an expr followed by ';' */ stmt ::= G_ENDS. -stmt ::= expr(A) G_ENDS. { pEval->setRoot(A); } -//stmt ::= expr G_SEMCOL. { pEval->setRoot(NULL) } +stmt ::= expr(A) G_ENDS. { pEval->setRoot(A); } +//stmt ::= expr G_SEMCOL. { pEval->setRoot(NULL); } -expr(A) ::= G_VALUE(B). { A.op = TR_NUMBER; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; } -expr(A) ::= G_VALUE(B) G_UNIT(C). { A.op = TR_NUMBER; A.value = B.value; A.leaf[0] = newNode( TR_UNIT, C.value.type, ""); A.leaf[1] = NULL; A.valid = true; } -expr(A) ::= G_STRING(B). { A.op = TR_STRING; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; } -expr(A) ::= G_IDENTIFIER(B). { A.op = TR_IDENTIFIER; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; } -expr(A) ::= expr(B) G_LESS_THAN expr(C). { A.op = TR_OP_LESS; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_GREATER_THAN expr(C). { A.op = TR_OP_GREATER; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_LESS_EQUAL_THAN expr(C). { A.op = TR_OP_LESS_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_GREATER_EQUAL_THAN expr(C). { A.op = TR_OP_GREATER_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_NOT_EQUAL expr(C). { A.op = TR_OP_NOT_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_BOOL_AND expr(C). { A.op = TR_OP_BOOL_AND; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_BOOL_OR expr(C). { A.op = TR_OP_BOOL_OR; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_PLUS expr(C). { A.op = TR_OP_ADD; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_MINUS expr(C). { A.op = TR_OP_SUB; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_MULT expr(C). { A.op = TR_OP_MUL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_DIVIDE expr(C). { A.op = TR_OP_DIV; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } -expr(A) ::= expr(B) G_EQUAL expr(C). { A.op = TR_OP_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } +expr(A) ::= G_VALUE(B). { A.op = TR_NUMBER; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= G_VALUE(B) G_UNIT(C). { A.op = TR_NUMBER; A.value = B.value; A.leaf[0] = newNode(TR_UNIT, C.value.type, ""); A.leaf[1] = NULL; A.valid = true; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= G_STRING(B). { A.op = TR_STRING; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= G_IDENTIFIER(B). { A.op = TR_IDENTIFIER; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_LESS_THAN expr(C). { A.op = TR_OP_LESS; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_GREATER_THAN expr(C). { A.op = TR_OP_GREATER; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_LESS_EQUAL_THAN expr(C). { A.op = TR_OP_LESS_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_GREATER_EQUAL_THAN expr(C). { A.op = TR_OP_GREATER_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_NOT_EQUAL expr(C). { A.op = TR_OP_NOT_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_BOOL_AND expr(C). { A.op = TR_OP_BOOL_AND; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_BOOL_OR expr(C). { A.op = TR_OP_BOOL_OR; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_PLUS expr(C). { A.op = TR_OP_ADD; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_MINUS expr(C). { A.op = TR_OP_SUB; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_MULT expr(C). { A.op = TR_OP_MUL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_DIVIDE expr(C). { A.op = TR_OP_DIV; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= expr(B) G_EQUAL expr(C). { A.op = TR_OP_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } -expr(A) ::= expr(B) G_STRUCT_REF expr(C). { A.op = TR_STRUCT_REF; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; } +expr(A) ::= expr(B) G_STRUCT_REF expr(C). { A.op = TR_STRUCT_REF; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); } -expr(A) ::= G_PARENL expr(B) G_PARENR. { A.op = B.op; A.value = B.value; A.valid=B.valid; A.leaf[0] = B.leaf[0]; A.leaf[1] = B.leaf[1]; } -expr(A) ::= G_IDENTIFIER(func_name) G_PARENL expr(B) G_PARENR. { A.op = TR_OP_FUNC_CALL; A.leaf[0] = copyNode(func_name); A.leaf[1] = copyNode(B); A.valid=1; } +expr(A) ::= G_PARENL expr(B) G_PARENR. { A.op = B.op; A.value = B.value; A.valid=B.valid; A.leaf[0] = B.leaf[0]; A.leaf[1] = B.leaf[1]; A.srcPos = pEval->GetSourcePos(); } +expr(A) ::= G_IDENTIFIER(F) G_PARENL expr(B) G_PARENR. { A.op = TR_OP_FUNC_CALL; A.leaf[0] = copyNode(F); A.leaf[1] = copyNode(B); A.valid = true; A.srcPos = pEval->GetSourcePos(); } diff --git a/common/libeval_compiler/libeval_compiler.cpp b/common/libeval_compiler/libeval_compiler.cpp index 35f4dbeb93..ae3afb1430 100644 --- a/common/libeval_compiler/libeval_compiler.cpp +++ b/common/libeval_compiler/libeval_compiler.cpp @@ -18,6 +18,7 @@ along with this program. If not, see . */ +#include #include #include @@ -67,18 +68,20 @@ static const std::string formatOpName( int op ) { int op; std::string mnemonic; - } simpleOps[] = { { TR_OP_MUL, "MUL" }, { TR_OP_DIV, "DIV" }, { TR_OP_ADD, "ADD" }, + } + simpleOps[] = + { + { TR_OP_MUL, "MUL" }, { TR_OP_DIV, "DIV" }, { TR_OP_ADD, "ADD" }, { TR_OP_SUB, "SUB" }, { TR_OP_LESS, "LESS" }, { TR_OP_GREATER, "GREATER" }, { TR_OP_LESS_EQUAL, "LESS_EQUAL" }, { TR_OP_GREATER_EQUAL, "GREATER_EQUAL" }, { TR_OP_EQUAL, "EQUAL" }, { TR_OP_NOT_EQUAL, "NEQUAL" }, { TR_OP_BOOL_AND, "AND" }, - { TR_OP_BOOL_OR, "OR" }, { TR_OP_BOOL_NOT, "NOT" }, { -1, "" } }; + { TR_OP_BOOL_OR, "OR" }, { TR_OP_BOOL_NOT, "NOT" }, { -1, "" } + }; for( int i = 0; simpleOps[i].op >= 0; i++ ) { if( simpleOps[i].op == op ) - { return simpleOps[i].mnemonic; - } } return "???"; @@ -87,32 +90,40 @@ static const std::string formatOpName( int op ) std::string UOP::Format() const { - char str[1024]; + char str[LIBEVAL_MAX_LITERAL_LENGTH]; switch( m_op ) { case TR_UOP_PUSH_VAR: - sprintf( str, "PUSH VAR [%p]", m_arg ); + snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH VAR [%p]", m_arg ); break; + case TR_UOP_PUSH_VALUE: { - auto val = reinterpret_cast( m_arg ); - if( val->GetType() == VT_NUMERIC ) - sprintf( str, "PUSH NUM [%.10f]", val->AsDouble() ); + VALUE* val = reinterpret_cast( m_arg ); + + if( !val ) + snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH nullptr" ); + else if( val->GetType() == VT_NUMERIC ) + snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH NUM [%.10f]", val->AsDouble() ); else - sprintf( str, "PUSH STR [%s]", val->AsString().c_str() ); - break; + snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH STR [%s]", val->AsString().c_str() ); } + break; + case TR_OP_METHOD_CALL: - sprintf(str, "MCALL" ); + snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "MCALL" ); break; + case TR_OP_FUNC_CALL: - sprintf(str, "FCALL" ); + snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "FCALL" ); break; + default: - sprintf( str, "%s %d", formatOpName( m_op ).c_str(), m_op ); + snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "%s %d", formatOpName( m_op ).c_str(), m_op ); break; } + return str; } @@ -140,7 +151,7 @@ std::string TOKENIZER::GetChars( std::function cond ) const return rv; } -bool TOKENIZER::MatchAhead( std::string match, std::function stopCond ) const +bool TOKENIZER::MatchAhead( const std::string& match, std::function stopCond ) const { int remaining = m_str.length() - m_pos; if( remaining < (int) match.length() ) @@ -158,11 +169,10 @@ COMPILER::COMPILER() { m_errorStatus.pendingError = false; m_localeDecimalSeparator = '.'; - m_parseFinished = false; - m_unitResolver.reset( new UNIT_RESOLVER ); + m_sourcePos = 0; + m_parseFinished = false; + m_unitResolver = std::make_unique(); m_parser = LIBEVAL::ParseAlloc( malloc ); - m_parseError = false; - m_parseErrorPos = 0; m_tree = nullptr; } @@ -207,7 +217,7 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode ) newString( aString ); m_errorStatus.pendingError = false; - m_tree = nullptr; + m_tree = nullptr; m_parseFinished = false; T_TOKEN tok; @@ -221,6 +231,8 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode ) do { + m_sourcePos = m_tokenizer.GetPos(); + tok = getToken(); libeval_dbg(10, "parse: tok %d\n", tok.token ); Parse( m_parser, tok.token, tok.value, this ); @@ -228,9 +240,8 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode ) if( m_errorStatus.pendingError ) { m_errorStatus.stage = ERROR_STATUS::CST_PARSE; - m_errorStatus.failingPosition = m_tokenizer.GetPos(); - m_errorStatus.failingObject = tok.value.value.str; - m_errorStatus.message = "Parse error"; + m_errorStatus.message.Printf( _( "Unrecognized token '%s'" ), tok.value.value.str ); + m_errorStatus.srcPos = m_tokenizer.GetPos(); return false; } @@ -261,7 +272,6 @@ COMPILER::T_TOKEN COMPILER::getToken() bool done = false; do { - switch( m_lexerState ) { case LS_DEFAULT: @@ -280,7 +290,7 @@ COMPILER::T_TOKEN COMPILER::getToken() bool COMPILER::lexString( COMPILER::T_TOKEN& aToken ) { - auto str = m_tokenizer.GetChars( []( int c ) -> bool { return c != '"'; } ); + auto str = m_tokenizer.GetChars( []( int c ) -> bool { return c != '\''; } ); //printf("STR LIT '%s'\n", (const char *)str.c_str() ); aToken.token = G_STRING; @@ -310,6 +320,7 @@ int COMPILER::resolveUnits() return -1; } + bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken ) { T_TOKEN retval; @@ -326,38 +337,44 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken ) return true; } - auto isDecimalSeparator = [&]( char ch ) -> bool { - return ( ch == m_localeDecimalSeparator || ch == '.' || ch == ',' ); - }; + auto isDecimalSeparator = + [&]( char ch ) -> bool + { + return ( ch == m_localeDecimalSeparator || ch == '.' || ch == ',' ); + }; // Lambda: get value as string, store into clToken.token and update current index. - auto extractNumber = [&]() { - bool haveSeparator = false; - idx = 0; - auto ch = m_tokenizer.GetChar(); + auto extractNumber = + [&]() + { + bool haveSeparator = false; + idx = 0; + int ch = m_tokenizer.GetChar(); - do - { - if( isDecimalSeparator( ch ) && haveSeparator ) - break; + do + { + if( isDecimalSeparator( ch ) && haveSeparator ) + break; - current.append( 1, ch ); + current.append( 1, ch ); - if( isDecimalSeparator( ch ) ) - haveSeparator = true; + if( isDecimalSeparator( ch ) ) + haveSeparator = true; - m_tokenizer.NextChar(); - ch = m_tokenizer.GetChar(); - } while( isdigit( ch ) || isDecimalSeparator( ch ) ); + m_tokenizer.NextChar(); + ch = m_tokenizer.GetChar(); + } while( isdigit( ch ) || isDecimalSeparator( ch ) ); - // Ensure that the systems decimal separator is used - for( int i = current.length(); i; i-- ) - if( isDecimalSeparator( current[i - 1] ) ) - current[i - 1] = m_localeDecimalSeparator; + // Ensure that the systems decimal separator is used + for( int i = current.length(); i; i-- ) + { + if( isDecimalSeparator( current[i - 1] ) ) + current[i - 1] = m_localeDecimalSeparator; + } - //printf("-> NUM: '%s'\n", (const char *) current.c_str() ); - }; + //printf("-> NUM: '%s'\n", (const char *) current.c_str() ); + }; int ch; @@ -398,7 +415,7 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken ) retval.token = G_UNIT; retval.value.value.type = convertFrom; } - else if( ch == '\"' ) // string literal + else if( ch == '\'' ) // string literal { //printf( "MATCH STRING LITERAL\n" ); m_lexerState = LS_STRING; @@ -488,9 +505,8 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken ) break; default: m_errorStatus.stage = ERROR_STATUS::CST_PARSE; - m_errorStatus.failingPosition = m_tokenizer.GetPos(); - m_errorStatus.failingObject = ch; - m_errorStatus.message = "Syntax error"; + m_errorStatus.message.Printf( _( "Unrecognized character '%c'" ), (char) ch ); + m_errorStatus.srcPos = m_tokenizer.GetPos(); break; /* invalid character */ } @@ -564,11 +580,10 @@ void dumpNode( std::string& buf, TREE_NODE* tok, int depth = 0 ) ERROR_STATUS COMPILER::GetErrorStatus() { - ERROR_STATUS dummy; - return dummy; + return m_errorStatus; } -void COMPILER::ReportError( const std::string aErrorMsg ) +void COMPILER::ReportError( const std::string& aErrorMsg ) { m_errorStatus.pendingError = true; m_errorStatus.message = aErrorMsg; @@ -585,9 +600,10 @@ bool COMPILER::generateUCode( UCODE* aCode ) std::vector stack; std::set visitedNodes; - auto visited = [&]( TREE_NODE* node ) -> bool { - return visitedNodes.find( node ) != visitedNodes.end(); - }; + auto visited = [&]( TREE_NODE* node ) -> bool + { + return visitedNodes.find( node ) != visitedNodes.end(); + }; assert( m_tree ); @@ -603,7 +619,7 @@ bool COMPILER::generateUCode( UCODE* aCode ) while( !stack.empty() ) { - auto node = stack.back(); + TREE_NODE* node = stack.back(); libeval_dbg( 4, "process node %p [op %d] [stack %lu]\n", node, node->op, (unsigned long)stack.size() ); @@ -623,47 +639,71 @@ bool COMPILER::generateUCode( UCODE* aCode ) { case TR_IDENTIFIER: { - auto vref = aCode->createVarRef( this, node->leaf[0]->value.str, node->leaf[1]->value.str ); + char* itemName = node->leaf[0]->value.str; + char* propName = node->leaf[1]->value.str; + VAR_REF* vref = aCode->createVarRef( this, itemName, propName ); if( m_errorStatus.pendingError ) { - libeval_dbg(4, "varref fail\n"); + 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 ); + } + return false; } + node->uop = makeUop( TR_UOP_PUSH_VAR, vref ); node->isTerminal = true; break; } case TR_OP_FUNC_CALL: { + char* itemName = node->leaf[0]->value.str; + VAR_REF* vref = aCode->createVarRef( this, itemName, "" ); - libeval_dbg(4, "got a method call... [%s], this = %s\n", node->leaf[1]->leaf[0]->value.str, node->leaf[0]->value.str); - auto vref = aCode->createVarRef( this, node->leaf[0]->value.str, ""); - auto func = aCode->createFuncCall( this, node->leaf[1]->leaf[0]->value.str ); + if( m_errorStatus.pendingError ) + { + m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN; + m_errorStatus.message.Printf( _( "Unrecognized item '%s'" ), itemName ); + m_errorStatus.srcPos = node->leaf[0]->srcPos - strlen( itemName ); + return false; + } - if(!func) + char* functionName = node->leaf[1]->leaf[0]->value.str; + auto func = aCode->createFuncCall( this, functionName ); + + if( !func ) { m_errorStatus.pendingError = true; m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN; - libeval_dbg(0, "unable to resolve func %s\n", node->leaf[1]->leaf[0]->value.str ); + m_errorStatus.message.Printf( _( "Unrecognized function '%s'" ), + functionName ); + m_errorStatus.srcPos = node->leaf[1]->leaf[0]->srcPos + 1; return false; - // fixme: generate a message } -// printf("cfc4 test\n"); - // func(nullptr, nullptr, nullptr); - visitedNodes.insert( node->leaf[0] ); visitedNodes.insert( node->leaf[1]->leaf[0] ); node->uop = makeUop( TR_OP_METHOD_CALL, func, vref ); node->isTerminal = false; - + } break; } } break; - } case TR_NUMBER: { @@ -711,15 +751,15 @@ bool COMPILER::generateUCode( UCODE* aCode ) } visitedNodes.insert( node ); + if(node->uop) aCode->AddOp(node->uop); - stack.pop_back(); + stack.pop_back(); } libeval_dbg(2,"DUMp: \n%s\n", aCode->Dump().c_str() ); - return true; } @@ -734,8 +774,8 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode ) auto value = ctx->AllocValue(); value->Set( reinterpret_cast( m_arg )->GetValue( ucode ) ); ctx->Push( value ); - break; } + break; case TR_UOP_PUSH_VALUE: ctx->Push( reinterpret_cast( m_arg ) ); @@ -745,15 +785,16 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode ) //printf("CALL METHOD %s\n" ); m_func( ucode, ctx, m_arg ); return; + default: break; } if( m_op & TR_OP_BINARY_MASK ) { - auto arg2 = ctx->Pop(); - auto arg1 = ctx->Pop(); - double result; + LIBEVAL::VALUE* arg2 = ctx->Pop(); + LIBEVAL::VALUE* arg1 = ctx->Pop(); + double result; switch( m_op ) { @@ -815,30 +856,22 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode ) } } + VALUE* UCODE::Run() { CONTEXT ctx; - for( const auto op : m_ucode ) + + for( UOP* op : m_ucode ) op->Exec( &ctx, this ); assert( ctx.SP() == 1 ); return ctx.Pop(); } -void UCODE::RuntimeError( const std::string aErrorMsg ) + +void UCODE::RuntimeError( const std::string& aErrorMsg ) { } -std::string ERROR_STATUS::Format() const -{ - if( !pendingError ) - return ""; - - char str[1024]; - sprintf(str,"%s (pos: %d, near: '%s')", message.c_str(), failingPosition, failingObject.c_str() ); - - return str; -} - } // namespace LIBEVAL diff --git a/common/project/net_settings.cpp b/common/project/net_settings.cpp index faa4eeaf49..045b0ae6cc 100644 --- a/common/project/net_settings.cpp +++ b/common/project/net_settings.cpp @@ -418,13 +418,26 @@ bool NET_SETTINGS::ParseBusGroup( wxString aGroup, wxString* aName, } -void NET_SETTINGS::ResolveNetClassAssignments() +void NET_SETTINGS::ResolveNetClassAssignments( bool aRebuildFromScratch ) { - std::map existing = m_NetClassAssignments; + std::map baseList = m_NetClassAssignments; + + if( aRebuildFromScratch ) + { + for( const std::pair& netclass : m_NetClasses ) + { + for( const wxString& net : *netclass.second ) + baseList[ net ] = netclass.second->GetName(); + } + } + else + { + baseList = m_NetClassAssignments; + } m_NetClassAssignments.clear(); - for( const auto& ii : existing ) + for( const auto& ii : baseList ) { m_NetClassAssignments[ ii.first ] = ii.second; diff --git a/common/property_mgr.cpp b/common/property_mgr.cpp index ee8569631b..47fd15b034 100644 --- a/common/property_mgr.cpp +++ b/common/property_mgr.cpp @@ -44,8 +44,8 @@ const wxString& PROPERTY_MANAGER::ResolveType( TYPE_ID aType ) const PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aProperty ) const { - wxASSERT_MSG( !m_dirty, "Have not called PROPERTY_MANAGER::Rebuild(), " - "property list not up-to-date" ); + if( m_dirty ) + const_cast( this )->Rebuild(); auto it = m_classes.find( aType ); @@ -54,7 +54,7 @@ PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aPr const CLASS_DESC& classDesc = it->second; - for( const auto& property : classDesc.m_allProperties ) + for( PROPERTY_BASE* property : classDesc.m_allProperties ) { if( !aProperty.CmpNoCase( property->Name() ) ) return property; @@ -66,8 +66,8 @@ PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aPr const PROPERTY_LIST& PROPERTY_MANAGER::GetProperties( TYPE_ID aType ) const { - wxASSERT_MSG( !m_dirty, "Have not called PROPERTY_MANAGER::Rebuild(), " - "property list not up-to-date" ); + if( m_dirty ) + const_cast( this )->Rebuild(); static const PROPERTY_LIST empty; auto it = m_classes.find( aType ); @@ -138,7 +138,7 @@ void PROPERTY_MANAGER::InheritsAfter( TYPE_ID aDerived, TYPE_ID aBase ) m_dirty = true; wxASSERT_MSG( derived.m_bases.size() == 1 || derived.m_typeCasts.count( aBase ) == 1, - "You need to add a TYPE_CAST for classes inheriting from multiple bases" ); + "You need to add a TYPE_CAST for classes inheriting from multiple bases" ); } @@ -163,12 +163,8 @@ bool PROPERTY_MANAGER::IsOfType( TYPE_ID aDerived, TYPE_ID aBase ) const void PROPERTY_MANAGER::Rebuild() { - wxASSERT_MSG( m_dirty, "Excessive Rebuild() call" ); - - for( auto& classEntry : m_classes ) - { + for( std::pair& classEntry : m_classes ) classEntry.second.rebuild(); - } m_dirty = false; } @@ -195,28 +191,31 @@ void PROPERTY_MANAGER::CLASS_DESC::rebuild() } -void PROPERTY_MANAGER::CLASS_DESC::collectPropsRecur( PROPERTY_LIST& aResult, PROPERTY_SET& aReplaced ) const +void PROPERTY_MANAGER::CLASS_DESC::collectPropsRecur( PROPERTY_LIST& aResult, + PROPERTY_SET& aReplaced ) const { - for( const auto& replacedEntry : m_replaced ) + for( const std::pair& replacedEntry : m_replaced ) aReplaced.emplace( replacedEntry ); - for( auto& propertyData : m_ownProperties ) + for( const std::pair>& prop : m_ownProperties ) { - PROPERTY_BASE* property = propertyData.second.get(); + PROPERTY_BASE* property = prop.second.get(); // Do not store replaced properties if( aReplaced.count( std::make_pair( property->OwnerHash(), property->Name() ) ) == 0 ) aResult.push_back( property ); } - for( const auto& base : m_bases ) + for( const std::reference_wrapper& base : m_bases ) base.get().collectPropsRecur( aResult, aReplaced ); } + std::vector PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aProperty ) { std::vector ids; - + +/* for( auto& cls : m_classes ) { CLASS_INFO info; @@ -224,26 +223,29 @@ std::vector PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aPrope for( auto prop : cls.second.m_allProperties ) info.properties.push_back(prop); - + } + */ return ids; } + PROPERTY_MANAGER::CLASSES_INFO PROPERTY_MANAGER::GetAllClasses() { CLASSES_INFO rv; - for( auto& cls : m_classes ) + + for( std::pair& classEntry : m_classes ) { CLASS_INFO info; - info.type = cls.first; - info.name = m_classNames[cls.first]; + info.type = classEntry.first; + info.name = m_classNames[classEntry.first]; - for( auto prop : cls.second.m_allProperties ) - info.properties.push_back(prop); + for( PROPERTY_BASE* prop : classEntry.second.m_allProperties ) + info.properties.push_back( prop ); - rv.push_back(info); + rv.push_back( info ); } return rv; diff --git a/eeschema/eeschema_config.cpp b/eeschema/eeschema_config.cpp index 5aa876f8b5..8f36a83391 100644 --- a/eeschema/eeschema_config.cpp +++ b/eeschema/eeschema_config.cpp @@ -268,7 +268,7 @@ void SCH_EDIT_FRAME::ShowSchematicSetupDialog( const wxString& aInitialPage ) if( dlg.ShowQuasiModal() == wxID_OK ) { - Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments(); + Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments( true ); SaveProjectSettings(); Kiway().CommonSettingsChanged( false, true ); diff --git a/include/board_design_settings.h b/include/board_design_settings.h index 6a75c7260c..7fc68e0fc9 100644 --- a/include/board_design_settings.h +++ b/include/board_design_settings.h @@ -219,14 +219,6 @@ public: std::vector m_ViasDimensionsList; std::vector m_DiffPairDimensionsList; - // List of netclasses. There is always the default netclass. - //NETCLASSES m_NetClasses; - std::vector m_DRCRuleSelectors; - std::vector m_DRCRules; - - // Temporary storage for rule matching. - std::vector m_matched; - bool m_MicroViasAllowed; ///< true to allow micro vias bool m_BlindBuriedViaAllowed; ///< true to allow blind/buried vias VIATYPE m_CurrentViaType; ///< (VIA_BLIND_BURIED, VIA_THROUGH, VIA_MICROVIA) @@ -243,10 +235,9 @@ public: int m_CopperEdgeClearance; int m_HoleToHoleMin; // Min width of peninsula between two drilled holes - std::map< int, int > m_DRCSeverities; // Map from DRCErrorCode to SEVERITY - - /// Excluded DRC items - std::set m_DrcExclusions; + std::vector m_DRCRules; + std::map< int, int > m_DRCSeverities; // Map from DRCErrorCode to SEVERITY + std::set m_DrcExclusions; /** Option to handle filled polygons in zones: * the "legacy" option is using thick outlines around filled polygons: give the best shape diff --git a/include/class_board_item.h b/include/class_board_item.h index 49e0482a7e..22277e4994 100644 --- a/include/class_board_item.h +++ b/include/class_board_item.h @@ -354,4 +354,49 @@ protected: DECLARE_ENUM_TO_WXANY( PCB_LAYER_ID ); #endif + +/** + * A singleton item of this class is returned for a weak reference that no longer exists. + * Its sole purpose is to flag the item as having been deleted. + */ +class DELETED_BOARD_ITEM : public BOARD_ITEM +{ +public: + DELETED_BOARD_ITEM() : + BOARD_ITEM( nullptr, NOT_USED ) + {} + + wxString GetSelectMenuText( EDA_UNITS aUnits ) const override + { + return _( "(Deleted Item)" ); + } + + wxString GetClass() const override + { + return wxT( "DELETED_BOARD_ITEM" ); + } + + // pure virtuals: + void SetPosition( const wxPoint& ) override {} + + wxPoint GetPosition() const override { + return wxPoint(0, 0); + } + + static DELETED_BOARD_ITEM* GetInstance() + { + static DELETED_BOARD_ITEM* item = nullptr; + + if( !item ) + item = new DELETED_BOARD_ITEM(); + + return item; + } + +#if defined(DEBUG) + void Show( int , std::ostream& ) const override {} +#endif +}; + + #endif /* BOARD_ITEM_STRUCT_H */ diff --git a/include/libeval_compiler/libeval_compiler.h b/include/libeval_compiler/libeval_compiler.h index 5724232095..cf2c73eb4d 100644 --- a/include/libeval_compiler/libeval_compiler.h +++ b/include/libeval_compiler/libeval_compiler.h @@ -57,20 +57,18 @@ class COMPILER; struct ERROR_STATUS { - bool pendingError; + bool pendingError; - enum STAGE { - CST_PARSE = 0, - CST_CODEGEN, - CST_RUNTIME - }; + enum STAGE + { + CST_PARSE = 0, + CST_CODEGEN, + CST_RUNTIME + }; - STAGE stage; - std::string message; - std::string failingObject; - int failingPosition; - - std::string Format() const; + STAGE stage; + wxString message; // Note: use wxString for GUI-related strings + int srcPos; }; @@ -108,158 +106,155 @@ struct TREE_NODE UOP* uop; bool valid; bool isTerminal; + int srcPos; }; static inline TREE_NODE* copyNode( TREE_NODE& t ) { - auto t2 = new TREE_NODE(); - t2->valid = t.valid; + auto t2 = new TREE_NODE(); + t2->valid = t.valid; snprintf( t2->value.str, LIBEVAL_MAX_LITERAL_LENGTH, "%s", t.value.str ); - t2->op = t.op; - t2->value.type = t.value.type; - t2->leaf[0] = t.leaf[0]; - t2->leaf[1] = t.leaf[1]; - t2->isTerminal = false; - t2->uop = nullptr; + t2->op = t.op; + t2->value.type = t.value.type; + t2->leaf[0] = t.leaf[0]; + t2->leaf[1] = t.leaf[1]; + t2->isTerminal = false; + t2->srcPos = t.srcPos; + t2->uop = nullptr; return t2; } static inline TREE_NODE* newNode( int op, int type, const std::string& value ) { - auto t2 = new TREE_NODE(); - t2->valid = true; + auto t2 = new TREE_NODE(); + t2->valid = true; snprintf( t2->value.str, LIBEVAL_MAX_LITERAL_LENGTH, "%s", value.c_str() ); - t2->op = op; - t2->value.type = type; - t2->leaf[0] = nullptr; - t2->leaf[1] = nullptr; - t2->isTerminal = false; - t2->uop = nullptr; + t2->op = op; + t2->value.type = type; + t2->leaf[0] = nullptr; + t2->leaf[1] = nullptr; + t2->isTerminal = false; + t2->srcPos = -1; + t2->uop = nullptr; return t2; } -class UNIT_RESOLVER { - public: - UNIT_RESOLVER() - { - } +class UNIT_RESOLVER +{ +public: + UNIT_RESOLVER() + { + } - virtual ~UNIT_RESOLVER() - { - } + virtual ~UNIT_RESOLVER() + { + } - virtual const std::vector& GetSupportedUnits() const - { - static const std::vector nullUnits; + virtual const std::vector& GetSupportedUnits() const + { + static const std::vector nullUnits; - return nullUnits; - } + return nullUnits; + } - virtual double Convert( const std::string aString, int unitType ) const - { - return 0.0; - }; + virtual double Convert( const std::string& aString, int unitType ) const + { + return 0.0; + }; }; -class VALUE { + +class VALUE +{ public: VALUE(): m_type(VT_UNDEFINED), m_valueDbl( 0 ) - {}; + {}; - VALUE( const std::string& aStr ) : + VALUE( std::string aStr ) : m_type( VT_STRING ), m_valueDbl( 0 ), - m_valueStr( aStr ) - {}; + m_valueStr( std::move( aStr ) ) + {}; VALUE( const double aVal ) : m_type( VT_NUMERIC ), m_valueDbl( aVal ) - {}; + {}; - double AsDouble() const - { - return m_valueDbl; - } + double AsDouble() const + { + return m_valueDbl; + } - const std::string& AsString() const - { - return m_valueStr; - } + const std::string& AsString() const + { + return m_valueStr; + } - bool operator==( const VALUE& b ) const - { - if( m_type != b.m_type ) - return false; - if( m_type == VT_NUMERIC && m_valueDbl != b.m_valueDbl ) - return false; - if( m_type == VT_STRING && m_valueStr != b.m_valueStr ) - return false; + bool operator==( const VALUE& b ) const + { + if( m_type == VT_NUMERIC && b.m_type == VT_NUMERIC ) + return m_valueDbl == b.m_valueDbl; + else if( m_type == VT_STRING && b.m_type == VT_STRING ) + return m_valueStr == b.m_valueStr; - return true; - } + return false; + } - + VAR_TYPE_T GetType() const { return m_type; }; - VAR_TYPE_T GetType() const { return m_type; }; + void Set( double aValue ) + { + m_type = VT_NUMERIC; + m_valueDbl = aValue; + } - void Set( double aValue ) - { - m_type = VT_NUMERIC; - m_valueDbl = aValue; - } + void Set( const std::string& aValue ) + { + m_type = VT_STRING; + m_valueStr = aValue; + } - void Set( std::string aValue ) - { - m_type = VT_STRING; - m_valueStr = aValue; - } + void Set( const VALUE &val ) + { + m_type = val.m_type; + m_valueDbl = val.m_valueDbl; - void Set( const VALUE &val ) - { - m_type = val.m_type; - m_valueDbl = val.m_valueDbl; - if(m_type == VT_STRING) + if( m_type == VT_STRING ) m_valueStr = val.m_valueStr; - - } + } - - bool EqualTo( const VALUE* v2 ) const - { - assert ( m_type == v2->m_type ); - if(m_type == VT_STRING) - return m_valueStr == v2->m_valueStr; - else - return m_valueDbl == v2->m_valueDbl; - } + bool EqualTo( const VALUE* v2 ) const + { + return operator==( *v2 ); + } private: - VAR_TYPE_T m_type; - double m_valueDbl; - std::string m_valueStr; - }; + VAR_TYPE_T m_type; + double m_valueDbl; + std::string m_valueStr; +}; + class UCODE; class VAR_REF - { - public: - virtual VAR_TYPE_T GetType( UCODE* aUcode ) = 0; - virtual VALUE GetValue( UCODE* aUcode ) = 0; - }; +{ +public: + virtual VAR_TYPE_T GetType() = 0; + virtual VALUE GetValue( UCODE* aUcode ) = 0; +}; class UCODE { public: - class CONTEXT { public: @@ -268,7 +263,8 @@ public: CONTEXT() { m_sp = 0; - for (int i = 0; i < c_memSize; i++ ) + + for( int i = 0; i < c_memSize; i++ ) m_memory.push_back( VALUE() ); } @@ -294,11 +290,12 @@ public: { return m_sp; } - private: - std::vector m_memory; - VALUE* m_stack[128]; - int m_sp = 0; - int m_memPos = 0; + + private: + std::vector m_memory; + VALUE* m_stack[128]; + int m_sp = 0; + int m_memPos = 0; }; typedef std::function FUNC_PTR; @@ -310,7 +307,7 @@ public: VALUE* Run(); std::string Dump() const; - void RuntimeError( const std::string aErrorMsg ); + void RuntimeError( const std::string& aErrorMsg ); virtual VAR_REF* createVarRef( COMPILER* aCompiler, const std::string& var, const std::string& field ) { @@ -328,21 +325,28 @@ private: class UOP - { - public: - UOP( int op, void* arg ) : m_op( op ), m_arg( arg ) - {}; - UOP( int op, UCODE::FUNC_PTR func, void *arg ) : m_op( op ), m_arg(arg), m_func( func ) - {}; +{ +public: + UOP( int op, void* arg ) : + m_op( op ), + m_arg( arg ) + {}; - void Exec( UCODE::CONTEXT* ctx, UCODE *ucode ); - std::string Format() const; + UOP( int op, UCODE::FUNC_PTR func, void *arg ) : + m_op( op ), + m_arg(arg), + m_func( std::move( func ) ) + {}; - private: - int m_op; - void *m_arg; - UCODE::FUNC_PTR m_func; - }; + void Exec( UCODE::CONTEXT* ctx, UCODE *ucode ); + + std::string Format() const; + +private: + int m_op; + void* m_arg; + UCODE::FUNC_PTR m_func; +}; class TOKENIZER { @@ -363,6 +367,7 @@ public: { if( m_pos >= m_str.length() ) return 0; + return m_str[m_pos]; } @@ -381,13 +386,13 @@ public: return m_pos; } - std::string GetChars( std::function cond ) const; - bool MatchAhead( std::string match, std::function stopCond ) const; + + bool MatchAhead( const std::string& match, std::function stopCond ) const; + private: std::string m_str; size_t m_pos; - }; @@ -397,7 +402,8 @@ public: COMPILER(); virtual ~COMPILER(); - /* clear() should be invoked by the client if a new input string is to be processed. It + /* + * clear() should be invoked by the client if a new input string is to be processed. It * will reset the parser. User defined variables are retained. */ void Clear(); @@ -406,17 +412,18 @@ public: void parseError( const char* s ); void parseOk(); + 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 setRoot( LIBEVAL::TREE_NODE root ); + bool Compile( const std::string& aString, UCODE* aCode ); - std::string DumpTree(); - void ReportError( const std::string aErrorMsg ); + void ReportError( const std::string& aErrorMsg ); ERROR_STATUS GetErrorStatus(); protected: @@ -446,9 +453,6 @@ protected: bool lexDefault( T_TOKEN& aToken ); bool lexString( T_TOKEN& aToken ); - /* Used by processing loop */ - void parse( int token, TREE_NODE value ); - int resolveUnits(); UOP* makeUop( int op, double value ) @@ -459,40 +463,35 @@ protected: UOP* makeUop( int op, std::string value ) { - auto uop = new UOP( op, new VALUE( value ) ); + UOP* uop = new UOP( op, new VALUE( std::move( value ) ) ); return uop; } UOP* makeUop( int op, VAR_REF* aRef = nullptr ) { - auto uop = new UOP( op, aRef ); + UOP* uop = new UOP( op, aRef ); return uop; } UOP* makeUop( int op, UCODE::FUNC_PTR aFunc, void *arg = nullptr ) { - auto uop = new UOP( op, aFunc, arg ); + UOP* uop = new UOP( op, std::move( aFunc ), arg ); return uop; } - /* Token state for input string. */ - void* m_parser; // the current lemon parser state machine - TOKENIZER m_tokenizer; - char m_localeDecimalSeparator; - - /* Parse progress. Set by parser actions. */ - bool m_parseError; - bool m_parseFinished; - std::string m_parseErrorMessage; - std::string m_parseErrorToken; - int m_parseErrorPos; + void* m_parser; // the current lemon parser state machine + TOKENIZER m_tokenizer; + char m_localeDecimalSeparator; std::unique_ptr m_unitResolver; - ERROR_STATUS m_errorStatus; - TREE_NODE* m_tree; + int m_sourcePos; + ERROR_STATUS m_errorStatus; + bool m_parseFinished; + + TREE_NODE* m_tree; }; diff --git a/include/project/net_settings.h b/include/project/net_settings.h index e3a3f393aa..ec1b103625 100644 --- a/include/project/net_settings.h +++ b/include/project/net_settings.h @@ -77,8 +77,11 @@ public: /** * Explodes the list of netclass assignments to include atomic members of composite labels * (buses). + * + * @param aRebuildFromScratch indicates the assignments should be rebuilt from the netclass + * membership lists before resolving. */ - void ResolveNetClassAssignments(); + void ResolveNetClassAssignments( bool aRebuildFromScratch = false ); private: // TODO: Add diff pairs, bus information, etc here. diff --git a/include/property.h b/include/property.h index 4a41e1ae41..04cfe4b258 100644 --- a/include/property.h +++ b/include/property.h @@ -526,6 +526,11 @@ public: return *this; } + void SetDefault( T aValue ) + { + m_default = aValue; + } + const wxString& ToString( T value ) const { return m_choices.GetLabel( static_cast( value ) ); @@ -533,7 +538,10 @@ public: const T ToEnum( const wxString value ) { - return m_reverseMap[value]; + if( m_reverseMap.count( value ) ) + return m_reverseMap[ value ]; + else + return m_default; } const wxPGChoices& Choices() const @@ -542,8 +550,9 @@ public: } private: - wxPGChoices m_choices; + wxPGChoices m_choices; std::unordered_map m_reverseMap; + T m_default; // Returned if the string is not recognized ENUM_MAP() { diff --git a/pcbnew/board_connected_item.cpp b/pcbnew/board_connected_item.cpp index 70b69793d1..8c848714d6 100644 --- a/pcbnew/board_connected_item.cpp +++ b/pcbnew/board_connected_item.cpp @@ -204,14 +204,14 @@ static struct BOARD_CONNECTED_ITEM_DESC { BOARD_CONNECTED_ITEM_DESC() { - auto& layerEnum = ENUM_MAP::Instance(); + ENUM_MAP& layerEnum = ENUM_MAP::Instance(); if( layerEnum.Choices().GetCount() == 0 ) { + layerEnum.SetDefault( UNDEFINED_LAYER ); + for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq ) - { layerEnum.Map( *seq, LSET::Name( *seq ) ); - } } PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp index 9a9652447c..f1f78254c9 100644 --- a/pcbnew/board_design_settings.cpp +++ b/pcbnew/board_design_settings.cpp @@ -590,9 +590,7 @@ void BOARD_DESIGN_SETTINGS::initFromOther( const BOARD_DESIGN_SETTINGS& aOther ) m_TrackWidthList = aOther.m_TrackWidthList; m_ViasDimensionsList = aOther.m_ViasDimensionsList; m_DiffPairDimensionsList = aOther.m_DiffPairDimensionsList; - m_DRCRuleSelectors = aOther.m_DRCRuleSelectors; m_DRCRules = aOther.m_DRCRules; - m_matched = aOther.m_matched; m_MicroViasAllowed = aOther.m_MicroViasAllowed; m_BlindBuriedViaAllowed = aOther.m_BlindBuriedViaAllowed; m_CurrentViaType = aOther.m_CurrentViaType; diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 4c0f83080e..5bcc41977d 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -48,52 +48,6 @@ #include #include -/** - * A singleton item of this class is returned for a weak reference that no longer exists. - * Its sole purpose is to flag the item as having been deleted. - */ -class DELETED_BOARD_ITEM : public BOARD_ITEM -{ -public: - DELETED_BOARD_ITEM() : - BOARD_ITEM( nullptr, NOT_USED ) - {} - - wxString GetSelectMenuText( EDA_UNITS aUnits ) const override - { - return _( "(Deleted Item)" ); - } - - wxString GetClass() const override - { - return wxT( "DELETED_BOARD_ITEM" ); - } - - // pure virtuals: - void SetPosition( const wxPoint& ) override {} - - wxPoint GetPosition() const override { - return wxPoint(0, 0); - } - - static DELETED_BOARD_ITEM* GetInstance() - { - static DELETED_BOARD_ITEM* item = nullptr; - - if( !item ) - item = new DELETED_BOARD_ITEM(); - - return item; - } - -#if defined(DEBUG) - void Show( int , std::ostream& ) const override {} -#endif -}; - -DELETED_BOARD_ITEM* g_DeletedItem = nullptr; - - /* This is an odd place for this, but CvPcb won't link if it is * in class_board_item.cpp like I first tried it. */ diff --git a/pcbnew/class_board_item.cpp b/pcbnew/class_board_item.cpp index 49fdd795d2..342117dde1 100644 --- a/pcbnew/class_board_item.cpp +++ b/pcbnew/class_board_item.cpp @@ -1,8 +1,3 @@ -/** - * @file class_board_item.cpp - * @brief Class BOARD_ITEM definition and some basic functions. - */ - /* * This program source code file is part of KiCad, a free EDA CAD application. * @@ -29,7 +24,6 @@ */ #include -#include #include #include @@ -137,8 +131,9 @@ void BOARD_ITEM::SwapData( BOARD_ITEM* aImage ) } -void BOARD_ITEM::TransformShapeWithClearanceToPolygon( - SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const +void BOARD_ITEM::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, + int aClearanceValue, int aError, + bool ignoreLineWidth ) const { wxASSERT_MSG( false, "Called TransformShapeWithClearanceToPolygon() on unsupported BOARD_ITEM." ); }; @@ -148,14 +143,14 @@ static struct BOARD_ITEM_DESC { BOARD_ITEM_DESC() { - auto& layerEnum = ENUM_MAP::Instance(); + ENUM_MAP& layerEnum = ENUM_MAP::Instance(); if( layerEnum.Choices().GetCount() == 0 ) { + layerEnum.SetDefault( UNDEFINED_LAYER ); + for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq ) - { layerEnum.Map( *seq, LSET::Name( *seq ) ); - } } PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 92c3da2fba..4411f796ee 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -1647,8 +1647,8 @@ static struct MODULE_DESC &MODULE::SetValue, &MODULE::GetValue ) ); propMgr.AddProperty( new PROPERTY( _( "Orientation" ), &MODULE::SetOrientationDegrees, &MODULE::GetOrientationDegrees, PROPERTY_DISPLAY::DEGREE ) ); - //propMgr.AddProperty( new PROPERTY( _( "Local Clearance" ), -// &MODULE::SetLocalClearance, &MODULE::GetLocalClearance, PROPERTY_DISPLAY::DISTANCE ) ); + propMgr.AddProperty( new PROPERTY( _( "Local Clearance" ), + &MODULE::SetLocalClearance, &MODULE::GetLocalClearance, PROPERTY_DISPLAY::DISTANCE ) ); propMgr.AddProperty( new PROPERTY( _( "Local Solderpaste Margin" ), &MODULE::SetLocalSolderPasteMargin, &MODULE::GetLocalSolderPasteMargin, PROPERTY_DISPLAY::DISTANCE ) ); propMgr.AddProperty( new PROPERTY( _( "Local Solderpaste Margin Ratio" ), diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 7ff768e581..cf4456d36a 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -237,7 +237,10 @@ public: int GetLocalSolderMaskMargin() const { return m_LocalSolderMaskMargin; } void SetLocalSolderMaskMargin( int aMargin ) { m_LocalSolderMaskMargin = aMargin; } - int GetLocalClearance( wxString* aSource = nullptr ) const + int GetLocalClearance() const { return m_LocalClearance; } + void SetLocalClearance( int aClearance ) { m_LocalClearance = aClearance; } + + int GetLocalClearance( wxString* aSource ) const { if( aSource ) *aSource = wxString::Format( _( "footprint %s" ), GetReference() ); @@ -245,8 +248,6 @@ public: return m_LocalClearance; } - void SetLocalClearance( int aClearance ) { m_LocalClearance = aClearance; } - int GetLocalSolderPasteMargin() const { return m_LocalSolderPasteMargin; } void SetLocalSolderPasteMargin( int aMargin ) { m_LocalSolderPasteMargin = aMargin; } diff --git a/pcbnew/dialogs/panel_pcbnew_color_settings.cpp b/pcbnew/dialogs/panel_pcbnew_color_settings.cpp index b74d8c2586..581ab88d89 100644 --- a/pcbnew/dialogs/panel_pcbnew_color_settings.cpp +++ b/pcbnew/dialogs/panel_pcbnew_color_settings.cpp @@ -36,8 +36,7 @@ PANEL_PCBNEW_COLOR_SETTINGS::PANEL_PCBNEW_COLOR_SETTINGS( PCB_EDIT_FRAME* aFrame : PANEL_COLOR_SETTINGS( aParent ), m_frame( aFrame ), m_page( nullptr ), - m_titleBlock( nullptr ), - m_ws( nullptr ) + m_titleBlock( nullptr ) { // Currently this only applies to eeschema m_optOverrideColors->Hide(); diff --git a/pcbnew/dialogs/panel_pcbnew_color_settings.h b/pcbnew/dialogs/panel_pcbnew_color_settings.h index f23d159a1a..6af2872ab6 100644 --- a/pcbnew/dialogs/panel_pcbnew_color_settings.h +++ b/pcbnew/dialogs/panel_pcbnew_color_settings.h @@ -61,8 +61,6 @@ private: TITLE_BLOCK* m_titleBlock; - KIGFX::WS_PROXY_VIEW_ITEM* m_ws; - void createSwatches(); }; diff --git a/pcbnew/dialogs/panel_setup_rules.cpp b/pcbnew/dialogs/panel_setup_rules.cpp index 21e0332e4f..40b7446c68 100644 --- a/pcbnew/dialogs/panel_setup_rules.cpp +++ b/pcbnew/dialogs/panel_setup_rules.cpp @@ -189,12 +189,11 @@ bool PANEL_SETUP_RULES::TransferDataFromWindow() try { - std::vector dummySelectors; std::vector dummyRules; DRC_RULES_PARSER parser( m_frame->GetBoard(), m_textEditor->GetText(), _( "DRC rules" ) ); - parser.Parse( dummySelectors, dummyRules ); + parser.Parse( dummyRules ); } catch( PARSE_ERROR& pe ) { @@ -249,7 +248,7 @@ void PANEL_SETUP_RULES::OnSyntaxHelp( wxHyperlinkEvent& aEvent ) "
"
             "(rule \"copper keepout\"\r"
             "   (disallow track) (disallow via) (disallow zone)\r"
-            "   (condition \"A.name == no_copper\"))\r"
+            "   (condition \"A.name == 'no_copper'\"))\r"
             "\r"
             "(rule \"BGA neckdown\"\r"
             "   (constraint track_width (min 0.2mm) (opt 0.25mm))\r"
@@ -258,11 +257,11 @@ void PANEL_SETUP_RULES::OnSyntaxHelp( wxHyperlinkEvent& aEvent )
             "\r"
             "(rule HV\r"
             "   (constraint clearance (min 1.5mm))\r"
-            "   (condition \"A.netclass == HV\"))\r"
+            "   (condition \"A.netclass == 'HV'\"))\r"
             "\r"
             "(rule HV_HV\r"
             "   (constraint clearance (min 2.0mm))\r"
-            "   (condition \"A.netclass == HV && B.netclass == HV\"))\r"
+            "   (condition \"A.netclass == 'HV' && B.netclass == 'HV'\"))\r"
             "
"; HTML_MESSAGE_BOX dlg( m_parent, _( "Syntax Help" ) ); diff --git a/pcbnew/drc/drc.cpp b/pcbnew/drc/drc.cpp index 412437e325..320ce03be0 100644 --- a/pcbnew/drc/drc.cpp +++ b/pcbnew/drc/drc.cpp @@ -187,7 +187,6 @@ bool DRC::LoadRules() if( rulesFile.FileExists() ) { - m_ruleSelectors.clear(); m_rules.clear(); FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) ); @@ -197,12 +196,11 @@ bool DRC::LoadRules() try { DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); - parser.Parse( m_ruleSelectors, m_rules ); + parser.Parse( m_rules ); } catch( PARSE_ERROR& pe ) { // Don't leave possibly malformed stuff around for us to trip over - m_ruleSelectors.clear(); m_rules.clear(); wxSafeYield( m_editFrame ); @@ -214,10 +212,9 @@ bool DRC::LoadRules() } } - std::reverse( std::begin( m_ruleSelectors ), std::end( m_ruleSelectors ) ); + std::reverse( std::begin( m_rules ), std::end( m_rules ) ); BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); - bds.m_DRCRuleSelectors = m_ruleSelectors; bds.m_DRCRules = m_rules; return true; diff --git a/pcbnew/drc/drc.h b/pcbnew/drc/drc.h index 6330a84d56..10f88b15c5 100644 --- a/pcbnew/drc/drc.h +++ b/pcbnew/drc/drc.h @@ -132,7 +132,6 @@ private: bool m_drcRun; // indicates DRC has been run at least once bool m_footprintsTested; // indicates footprints were tested in last run - std::vector m_ruleSelectors; std::vector m_rules; // Temp variables for performance during a single DRC run diff --git a/pcbnew/drc/drc_rule.cpp b/pcbnew/drc/drc_rule.cpp index 36fb938177..35511f3458 100644 --- a/pcbnew/drc/drc_rule.cpp +++ b/pcbnew/drc/drc_rule.cpp @@ -27,6 +27,8 @@ #include #include #include +#include + /* * Rule tokens: @@ -52,8 +54,17 @@ * hole * * - * (rule "HV" (constraint clearance (min 200))) - * (rule "HV_external" (constraint clearance (min 400))) + * (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))) @@ -62,99 +73,83 @@ * (rule "neckdown" (constraint clearance (min 15))) * * (rule "disallowMicrovias" (disallow micro_via)) + * + * + testEvalExpr( "A.type == \"Pad\" && B.type == \"Pad\" && (A.onLayer(\"F.Cu\"))",VAL(0.0), false, &trackA, &trackB ); + return 0; + testEvalExpr( "A.Width > B.Width", VAL(0.0), false, &trackA, &trackB ); + testEvalExpr( "A.Width + B.Width", VAL(Mils2iu(10) + Mils2iu(20)), false, &trackA, &trackB ); + + testEvalExpr( "A.Netclass", VAL( (const char*) trackA.GetNetClassName().c_str() ), false, &trackA, &trackB ); + testEvalExpr( "(A.Netclass == \"HV\") && (B.netclass == \"otherClass\") && (B.netclass != \"F.Cu\")", VAL( 1.0 ), false, &trackA, &trackB ); + testEvalExpr( "A.Netclass + 1.0", VAL( 1.0 ), false, &trackA, &trackB ); + testEvalExpr( "A.type == \"Track\" && B.type == \"Track\" && A.layer == \"F.Cu\"", VAL(0.0), false, &trackA, &trackB ); + testEvalExpr( "(A.type == \"Track\") && (B.type == \"Track\") && (A.layer == \"F.Cu\")", VAL(0.0), false, &trackA, &trackB ); */ DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint ) { - // JEY TODO: the bulk of this will be replaced by Tom's expression evaluator - BOARD* board = aItem->GetBoard(); if( !board ) return nullptr; - NETCLASS* aNetclass = nullptr; - NETCLASS* bNetclass = nullptr; - - if( aItem->IsConnected() ) - aNetclass = static_cast( aItem )->GetEffectiveNetclass(); - - if( bItem && bItem->IsConnected() ) - bNetclass = static_cast( bItem )->GetEffectiveNetclass(); - - for( DRC_SELECTOR* candidate : board->GetDesignSettings().m_DRCRuleSelectors ) + for( DRC_RULE* rule : board->GetDesignSettings().m_DRCRules ) { - if( candidate->m_MatchNetclasses.size() == 2 ) + if( ( rule->m_ConstraintFlags & aConstraint ) > 0 ) { - if( !bItem ) - continue; - - NETCLASS* firstNetclass = candidate->m_MatchNetclasses[0].get(); - NETCLASS* secondNetclass = candidate->m_MatchNetclasses[1].get(); - - if( !( aNetclass == firstNetclass && bNetclass == secondNetclass ) - && !( aNetclass == secondNetclass && bNetclass == firstNetclass ) ) - { - continue; - } + if( rule->m_Condition.EvaluateFor( aItem, bItem ) ) + return rule; } - else if( candidate->m_MatchNetclasses.size() == 1 ) - { - NETCLASS* matchNetclass = candidate->m_MatchNetclasses[0].get(); - - if( matchNetclass != aNetclass && !( bItem && matchNetclass == bNetclass ) ) - continue; - } - - if( candidate->m_MatchTypes.size() == 2 ) - { - if( !bItem ) - continue; - - KICAD_T firstType[2] = { candidate->m_MatchTypes[0], EOT }; - KICAD_T secondType[2] = { candidate->m_MatchTypes[1], EOT }; - - if( !( aItem->IsType( firstType ) && bItem->IsType( secondType ) ) - && !( aItem->IsType( secondType ) && bItem->IsType( firstType ) ) ) - { - continue; - } - } - else if( candidate->m_MatchTypes.size() == 1 ) - { - KICAD_T matchType[2] = { candidate->m_MatchTypes[0], EOT }; - - if( !aItem->IsType( matchType ) && !( bItem && bItem->IsType( matchType ) ) ) - continue; - } - - if( candidate->m_MatchLayers.size() ) - { - PCB_LAYER_ID matchLayer = candidate->m_MatchLayers[0]; - - if( !aItem->GetLayerSet().test( matchLayer ) ) - continue; - } - - if( candidate->m_MatchAreas.size() ) - { - if( candidate->m_MatchAreas[0] == "$board" ) - { - // matches everything - } - else - { - // TODO: area/room matches... - } - } - - // All tests done; if we're still here then it matches - - if( ( candidate->m_Rule->m_ConstraintFlags & aConstraint ) > 0 ) - return candidate->m_Rule; } return nullptr; } +DRC_RULE_CONDITION::DRC_RULE_CONDITION() +{ + m_ucode = nullptr; +} + + +DRC_RULE_CONDITION::~DRC_RULE_CONDITION() +{ + delete m_ucode; +} + + +bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB ) +{ + BOARD_ITEM* a = const_cast( aItemA ); + BOARD_ITEM* b = aItemB ? const_cast( aItemB ) : DELETED_BOARD_ITEM::GetInstance(); + + m_ucode->SetItems( a, b ); + +// fixme: handle error conditions + return m_ucode->Run()->AsDouble() != 0.0; +} + + +bool DRC_RULE_CONDITION::Compile() +{ + PCB_EXPR_COMPILER compiler; + + if (!m_ucode) + m_ucode = new PCB_EXPR_UCODE; + + bool ok = compiler.Compile( (const char*) m_Expression.c_str(), m_ucode ); + + 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 03cbaa1947..05ebac687b 100644 --- a/pcbnew/drc/drc_rule.h +++ b/pcbnew/drc/drc_rule.h @@ -27,9 +27,11 @@ #include #include #include +#include class BOARD_ITEM; +class PCB_EXPR_UCODE; #define CLEARANCE_CONSTRAINT (1 << 0) @@ -50,6 +52,52 @@ class BOARD_ITEM; #define DISALLOW_FOOTPRINTS (1 << 9) +template +class MINOPTMAX +{ +public: + T Min() const { assert( m_hasMin ); return m_min; }; + T Max() const { assert( m_hasMax ); return m_max; }; + T Opt() const { assert( m_hasOpt ); return m_opt; }; + + bool HasMin() const { return m_hasMin; } + bool HasMax() const { return m_hasMax; } + bool HasOpt() const { return m_hasOpt; } + + void SetMin( T v ) { m_min = v; m_hasMin = true; } + void SetMax( T v ) { m_max = v; m_hasMax = true; } + void SetOpt( T v ) { m_opt = v; m_hasOpt = true; } + +private: + T m_min; + T m_opt; + T m_max; + bool m_hasMin = false; + bool m_hasOpt = false; + bool m_hasMax = false; +}; + + +class DRC_RULE_CONDITION +{ +public: + DRC_RULE_CONDITION(); + ~DRC_RULE_CONDITION(); + + bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB ); + bool Compile(); + LIBEVAL::ERROR_STATUS GetCompilationError(); + +public: + wxString m_Expression; + wxString m_TargetRuleName; + +private: + LIBEVAL::ERROR_STATUS m_compileError; + PCB_EXPR_UCODE* m_ucode; +}; + + class DRC_RULE { public: @@ -81,31 +129,11 @@ public: MINOPTMAX m_TrackConstraint; int m_MinHole; - wxString m_Condition; -}; - - -class DRC_SELECTOR -{ -public: - DRC_SELECTOR() : - m_Priority( 1 ), - m_Rule( nullptr ) - { } - -public: - std::vector m_MatchNetclasses; - std::vector m_MatchTypes; - std::vector m_MatchLayers; - std::vector m_MatchAreas; - - int m_Priority; // 0 indicates automatic priority generation - DRC_RULE* m_Rule; + DRC_RULE_CONDITION m_Condition; }; DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint ); - #endif // DRC_RULE_H diff --git a/pcbnew/drc/drc_rule_parser.cpp b/pcbnew/drc/drc_rule_parser.cpp index f4b92b90df..c41176573c 100644 --- a/pcbnew/drc/drc_rule_parser.cpp +++ b/pcbnew/drc/drc_rule_parser.cpp @@ -65,10 +65,8 @@ void DRC_RULES_PARSER::initLayerMap() } -void DRC_RULES_PARSER::Parse( std::vector& aSelectors, - std::vector& aRules ) +void DRC_RULES_PARSER::Parse( std::vector& aRules ) { - std::vector< std::pair > selectorRules; bool haveVersion = false; for( T token = NextTok(); token != T_EOF; token = NextTok() ) @@ -91,15 +89,6 @@ void DRC_RULES_PARSER::Parse( std::vector& aSelectors, NeedRIGHT(); break; - case T_selector: - { - wxString ruleName; - - aSelectors.push_back( parseDRC_SELECTOR( &ruleName ) ); - selectorRules.emplace_back( aSelectors.back(), ruleName ); - } - break; - case T_rule: aRules.push_back( parseDRC_RULE() ); break; @@ -108,118 +97,6 @@ void DRC_RULES_PARSER::Parse( std::vector& aSelectors, Expecting( "selector or rule" ); } } - - // Hook up the selectors to their rules - std::map ruleMap; - - for( DRC_RULE* rule : aRules ) - ruleMap[ rule->m_Name ] = rule; - - for( const std::pair& entry : selectorRules ) - { - if( ruleMap.count( entry.second ) ) - { - entry.first->m_Rule = ruleMap[ entry.second ]; - } - else - { - wxString errText = wxString::Format( _( "Rule \"%s\" not found." ), entry.second ); - THROW_PARSE_ERROR( errText, CurSource(), "", 0, 0 ); - } - } -} - - -DRC_SELECTOR* DRC_RULES_PARSER::parseDRC_SELECTOR( wxString* aRuleName ) -{ - NETCLASSES& netclasses = m_board->GetDesignSettings().GetNetClasses(); - DRC_SELECTOR* selector = new DRC_SELECTOR(); - T token; - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_match_netclass: - { - NeedSYMBOL(); - NETCLASSPTR netclass = netclasses.Find( FromUTF8() ); - - if( netclass ) - { - selector->m_MatchNetclasses.push_back( std::move( netclass ) ); - } - else - { - // Interesting situation here: if we don't inform the user they may have a typo - // and can't figure out why their rules don't work. - // If we do tell them then it gets really noisy if they're using a single rule - // file for a class of board. - } - - NeedRIGHT(); - } - break; - - case T_match_type: - switch( NextTok() ) - { - case T_track: selector->m_MatchTypes.push_back( PCB_TRACE_T ); break; - case T_via: selector->m_MatchTypes.push_back( PCB_LOCATE_STDVIA_T ); break; - case T_micro_via: selector->m_MatchTypes.push_back( PCB_LOCATE_UVIA_T ); break; - case T_buried_via: selector->m_MatchTypes.push_back( PCB_LOCATE_BBVIA_T ); break; - case T_pad: selector->m_MatchTypes.push_back( PCB_PAD_T ); break; - case T_zone: selector->m_MatchTypes.push_back( PCB_ZONE_AREA_T ); break; - case T_text: selector->m_MatchTypes.push_back( PCB_LOCATE_TEXT_T ); break; - case T_graphic: selector->m_MatchTypes.push_back( PCB_LOCATE_GRAPHIC_T ); break; - case T_hole: selector->m_MatchTypes.push_back( PCB_LOCATE_HOLE_T ); break; - case T_npth: selector->m_MatchTypes.push_back( PCB_LOCATE_NPTH_T ); break; - case T_pth: selector->m_MatchTypes.push_back( PCB_LOCATE_PTH_T ); break; - case T_board_edge: selector->m_MatchTypes.push_back( PCB_LOCATE_BOARD_EDGE_T ); break; - default: Expecting( "track, via, micro_via, buried_via, pad, zone, text, " - "graphic, hole, npth, pth, or board_edge" ); - } - NeedRIGHT(); - break; - - case T_match_layer: - NeedSYMBOL(); - - if( m_layerMap.count( curText ) ) - { - selector->m_MatchLayers.push_back( m_layerMap[ curText ] ); - } - else - { - wxString errText = wxString::Format( _( "Layer \"%s\" not found." ), - wxString( curText ) ); - THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); - } - - NeedRIGHT(); - break; - - case T_match_area: - // TODO - break; - - case T_rule: - NeedSYMBOL(); - *aRuleName = FromUTF8(); - NeedRIGHT(); - break; - - default: - Expecting( "match_netclass, match_type, match_layer, match_area, or rule" ); - } - } - - return selector; } @@ -269,7 +146,15 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE() case T_condition: NeedSYMBOL(); - rule->m_Condition = FromUTF8(); + rule->m_Condition.m_Expression = FromUTF8(); + + if( !rule->m_Condition.Compile() ) + { + LIBEVAL::ERROR_STATUS error = rule->m_Condition.GetCompilationError(); + THROW_PARSE_ERROR( error.message, CurSource(), CurLine(), CurLineNumber(), + CurOffset() + error.srcPos ); + } + NeedRIGHT(); break; diff --git a/pcbnew/drc/drc_rule_parser.h b/pcbnew/drc/drc_rule_parser.h index a8d4c80025..8a7864d4cf 100644 --- a/pcbnew/drc/drc_rule_parser.h +++ b/pcbnew/drc/drc_rule_parser.h @@ -43,13 +43,11 @@ 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& aSelectors, std::vector& aRules ); + void Parse( std::vector& aRules ); private: void initLayerMap(); - DRC_SELECTOR* parseDRC_SELECTOR( wxString* aRuleName ); - DRC_RULE* parseDRC_RULE(); void parseConstraint( DRC_RULE* aRule ); diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index e4667371db..2eed0b4c2c 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -653,7 +653,7 @@ void PCB_EDIT_FRAME::ShowBoardSetupDialog( const wxString& aInitialPage, const w if( dlg.ShowQuasiModal() == wxID_OK ) { - Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments(); + Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments( true ); GetBoard()->SynchronizeNetsAndNetClasses(); GetBoard()->GetDesignSettings().SetCurrentNetClass( NETCLASS::Default ); diff --git a/pcbnew/pcb_expr_evaluator.cpp b/pcbnew/pcb_expr_evaluator.cpp index a99b43aed7..bb9246f0d7 100644 --- a/pcbnew/pcb_expr_evaluator.cpp +++ b/pcbnew/pcb_expr_evaluator.cpp @@ -23,92 +23,94 @@ #include - +#include #include "class_board.h" #include "pcb_expr_evaluator.h" class PCB_EXPR_BUILTIN_FUNCTIONS { - public: +public: - using FPTR = LIBEVAL::UCODE::FUNC_PTR; + using FPTR = LIBEVAL::UCODE::FUNC_PTR; - PCB_EXPR_BUILTIN_FUNCTIONS(); + PCB_EXPR_BUILTIN_FUNCTIONS(); - static PCB_EXPR_BUILTIN_FUNCTIONS& Instance() + static PCB_EXPR_BUILTIN_FUNCTIONS& Instance() + { + static PCB_EXPR_BUILTIN_FUNCTIONS self; + return self; + } + + std::string tolower( const std::string& str ) const + { + std::string rv; + std::transform( str.begin(), str.end(), rv.begin(), ::tolower ); + return rv; + } + + FPTR Get( const std::string &name ) const + { + auto it = m_funcs.find( name ); + + if( it == m_funcs.end() ) + return nullptr; + + return it->second; + } + +private: + std::map m_funcs; + + static void onLayer( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self ) + { + LIBEVAL::VALUE* arg = aCtx->Pop(); + PCB_EXPR_VAR_REF* vref = static_cast( self ); + PCB_LAYER_ID layer = ENUM_MAP::Instance().ToEnum( arg->AsString() ); + BOARD_ITEM* item = vref->GetObject( aUcode ); + LIBEVAL::VALUE* rv = aCtx->AllocValue(); + + rv->Set( item->IsOnLayer( layer ) ? 1.0 : 0.0 ); + aCtx->Push( rv ); + } + + static void isPlated( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self ) + { + PCB_EXPR_VAR_REF* vref = static_cast( self ); + BOARD_ITEM* item = vref->GetObject( aUcode ); + bool result = false; + + if( item->Type() == PCB_PAD_T ) { - static PCB_EXPR_BUILTIN_FUNCTIONS self; - return self; + D_PAD* pad = static_cast( item ); + result = pad->GetAttribute() == PAD_ATTRIB_STANDARD; } - std::string tolower( const std::string str ) const - { - std::string rv; - std::transform(str.begin(), - str.end(), - rv.begin(), - ::tolower); - return rv; - } - - FPTR Get( const std::string &name ) const - { - auto it = m_funcs.find( name ); - - if( it == m_funcs.end() ) - return nullptr; - - return it->second; - } - - private: - - std::map m_funcs; - - static void onLayer( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self ) - { - auto arg = aCtx->Pop(); - auto vref = static_cast( self ); - auto conv = ENUM_MAP::Instance(); - bool value = vref->GetObject(aUcode)->IsOnLayer( conv.ToEnum( arg->AsString() ) ); - auto rv = aCtx->AllocValue(); - rv->Set( value ? 1.0 : 0.0 ); - aCtx->Push( rv ); - } - - static void isPlated( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self ) - { - auto vref = static_cast( self ); - auto item = vref->GetObject(aUcode); - bool result = false; - if( item->Type() == PCB_PAD_T ) - { - auto pad = static_cast( item ); - result = pad->GetAttribute() == PAD_ATTRIB_STANDARD; - } - auto rv = aCtx->AllocValue(); - rv->Set( result ? 1.0 : 0.0 ); - aCtx->Push( rv ); - } + LIBEVAL::VALUE* rv = aCtx->AllocValue(); + rv->Set( result ? 1.0 : 0.0 ); + aCtx->Push( rv ); + } }; + PCB_EXPR_BUILTIN_FUNCTIONS::PCB_EXPR_BUILTIN_FUNCTIONS() { m_funcs[ "onlayer" ] = onLayer; m_funcs[ "isplated" ] = isPlated; } + BOARD_ITEM* PCB_EXPR_VAR_REF::GetObject( LIBEVAL::UCODE* aUcode ) const { - auto ucode = static_cast( aUcode ); - auto item = ucode->GetItem( m_itemIndex ); + const PCB_EXPR_UCODE* ucode = static_cast( aUcode ); + BOARD_ITEM* item = ucode->GetItem( m_itemIndex ); return item; } + LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode ) { - auto item = GetObject( aUcode ); - auto it = m_matchingTypes.find( TYPE_HASH( *item ) ); + BOARD_ITEM* item = const_cast( GetObject( aUcode ) ); + auto it = m_matchingTypes.find( TYPE_HASH( *item ) ); if( it == m_matchingTypes.end() ) { @@ -128,7 +130,9 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode ) { //printf("item %p Get string '%s'\n", item, (const char*) it->second->Name().c_str() ); str = item->Get( it->second ); - } else { + } + else + { const auto& any = item->Get( it->second ); any.GetAs( &str ); //printf("item %p get enum: '%s'\n", item , (const char*) str.c_str() ); @@ -138,26 +142,42 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode ) } } -LIBEVAL::UCODE::FUNC_PTR PCB_EXPR_UCODE::createFuncCall( LIBEVAL::COMPILER* aCompiler, const std::string& name ) + +LIBEVAL::UCODE::FUNC_PTR PCB_EXPR_UCODE::createFuncCall( LIBEVAL::COMPILER* aCompiler, + const std::string& name ) { - auto registry = PCB_EXPR_BUILTIN_FUNCTIONS::Instance(); - auto f = registry.Get( name ); + PCB_EXPR_BUILTIN_FUNCTIONS& registry = PCB_EXPR_BUILTIN_FUNCTIONS::Instance(); + + auto f = registry.Get( boost::to_lower_copy( name ) ); return f; } + LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, - const std::string& var, const std::string& field ) + const std::string& var, const std::string& field ) { PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); + PCB_EXPR_VAR_REF* vref = nullptr; - auto classes = propMgr.GetAllClasses(); - auto vref = new PCB_EXPR_VAR_REF( var == "A" ? 0 : 1 ); + if( var == "A" ) + { + vref = new PCB_EXPR_VAR_REF( 0 ); + } + else if( var == "B" ) + { + vref = new PCB_EXPR_VAR_REF( 1 ); + } + else + { + aCompiler->ReportError( "var" ); + return vref; + } if( field.empty() ) // return reference to base object return vref; - for( auto cls : classes ) + for( const PROPERTY_MANAGER::CLASS_INFO& cls : propMgr.GetAllClasses() ) { if( propMgr.IsOfType( cls.type, TYPE_HASH( BOARD_ITEM ) ) ) { @@ -167,10 +187,15 @@ LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, { //printf("Field '%s' class %s ptr %p haschoices %d typeid %s\n", field.c_str(), (const char *) cls.name.c_str(), prop, !!prop->HasChoices(), typeid(*prop).name() ); vref->AddAllowedClass( cls.type, prop ); + if( prop->TypeHash() == TYPE_HASH( int ) ) + { vref->SetType( LIBEVAL::VT_NUMERIC ); + } else if( prop->TypeHash() == TYPE_HASH( wxString ) ) + { vref->SetType( LIBEVAL::VT_STRING ); + } else if ( prop->HasChoices() ) { // it's an enum, we treat it as string vref->SetType( LIBEVAL::VT_STRING ); @@ -186,6 +211,9 @@ LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, } } + if( vref->GetType() == LIBEVAL::VT_UNDEFINED ) + aCompiler->ReportError( "field" ); + return vref; } @@ -204,19 +232,16 @@ public: return pcbUnits; } - virtual double Convert( const std::string aString, int unitId ) const override + virtual double Convert( const std::string& aString, int unitId ) const override { double v = atof( aString.c_str() ); + switch( unitId ) { - case 0: - return Mils2iu( v ); - case 1: - return Millimeter2iu( v ); - case 2: - return Mils2iu( v * 1000.0 ); - default: - return v; + case 0: return Mils2iu( v ); + case 1: return Millimeter2iu( v ); + case 2: return Mils2iu( v * 1000.0 ); + default: return v; } }; }; diff --git a/pcbnew/pcb_expr_evaluator.h b/pcbnew/pcb_expr_evaluator.h index b124b35ab3..6e94fae92d 100644 --- a/pcbnew/pcb_expr_evaluator.h +++ b/pcbnew/pcb_expr_evaluator.h @@ -66,6 +66,7 @@ class PCB_EXPR_VAR_REF : public LIBEVAL::VAR_REF public: PCB_EXPR_VAR_REF( int aItemIndex ) : m_itemIndex( aItemIndex ), + m_type( LIBEVAL::VT_UNDEFINED ), m_isEnum( false ) { //printf("*** createVarRef %p %d\n", this, aItemIndex ); @@ -84,7 +85,7 @@ public: m_matchingTypes[type_hash] = prop; } - virtual LIBEVAL::VAR_TYPE_T GetType( LIBEVAL::UCODE* aUcode ) override + virtual LIBEVAL::VAR_TYPE_T GetType() override { return m_type; } @@ -98,7 +99,7 @@ private: std::unordered_map m_matchingTypes; int m_itemIndex; LIBEVAL::VAR_TYPE_T m_type; - bool m_isEnum; + bool m_isEnum; }; @@ -116,10 +117,7 @@ public: ~PCB_EXPR_EVALUATOR(); bool Evaluate( const wxString& aExpr ); - int Result() const - { - return m_result; - } + int Result() const { return m_result; } wxString GetErrorString(); private: diff --git a/qa/drc_proto/drc.cpp b/qa/drc_proto/drc.cpp index 055aaac81d..0a8de43e97 100644 --- a/qa/drc_proto/drc.cpp +++ b/qa/drc_proto/drc.cpp @@ -186,7 +186,6 @@ bool DRC::LoadRules() if( rulesFile.FileExists() ) { - m_ruleSelectors.clear(); m_rules.clear(); FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) ); @@ -196,12 +195,11 @@ bool DRC::LoadRules() try { DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); - parser.Parse( m_ruleSelectors, m_rules ); + parser.Parse( m_rules ); } catch( PARSE_ERROR& pe ) { // Don't leave possibly malformed stuff around for us to trip over - m_ruleSelectors.clear(); m_rules.clear(); wxSafeYield( m_editFrame ); diff --git a/qa/drc_proto/drc_rule.cpp b/qa/drc_proto/drc_rule.cpp index 5302d73767..c321e78a48 100644 --- a/qa/drc_proto/drc_rule.cpp +++ b/qa/drc_proto/drc_rule.cpp @@ -47,23 +47,26 @@ test::DRC_RULE_CONDITION::DRC_RULE_CONDITION() m_ucode = nullptr; } + test::DRC_RULE_CONDITION::~DRC_RULE_CONDITION() { - if( m_ucode ) - delete m_ucode; + delete m_ucode; } -bool test::DRC_RULE_CONDITION::EvaluateFor( BOARD_ITEM* aItemA, BOARD_ITEM* aItemB ) + +bool test::DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB ) { - m_ucode->SetItems( aItemA, aItemB ); + m_ucode->SetItems( const_cast( aItemA ), const_cast( aItemB ) ); // fixme: handle error conditions return m_ucode->Run()->AsDouble() != 0.0; } + bool test::DRC_RULE_CONDITION::Compile() { PCB_EXPR_COMPILER compiler; + if (!m_ucode) m_ucode = new PCB_EXPR_UCODE; @@ -74,11 +77,12 @@ bool test::DRC_RULE_CONDITION::Compile() m_compileError = compiler.GetErrorStatus(); - printf("Fail: %s", m_compileError.Format().c_str() ); + printf( "Fail: %s", m_compileError.Format().c_str() ); return false; } + 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 669178576d..7b1da87a8d 100644 --- a/qa/drc_proto/drc_rule.h +++ b/qa/drc_proto/drc_rule.h @@ -130,7 +130,7 @@ public: DRC_RULE_CONDITION(); ~DRC_RULE_CONDITION(); - bool EvaluateFor( BOARD_ITEM* aItemA, BOARD_ITEM* aItemB ); + bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB ); bool Compile(); LIBEVAL::ERROR_STATUS GetCompilationError(); @@ -140,7 +140,7 @@ public: private: LIBEVAL::ERROR_STATUS m_compileError; - PCB_EXPR_UCODE* m_ucode; + PCB_EXPR_UCODE* m_ucode; }; diff --git a/qa/libeval_compiler/libeval_compiler_test.cpp b/qa/libeval_compiler/libeval_compiler_test.cpp index f729743bf8..0c3c9890cd 100644 --- a/qa/libeval_compiler/libeval_compiler_test.cpp +++ b/qa/libeval_compiler/libeval_compiler_test.cpp @@ -118,20 +118,20 @@ int main( int argc, char *argv[] ) trackA.SetWidth( Mils2iu( 10 )); trackB.SetWidth( Mils2iu( 20 )); - printf("TrkA %p netclass '%s'\n", &trackA, (const char*) trackA.GetNetClassName().c_str() ); - printf("TrkB %p netclass '%s'\n", &trackB, (const char*) trackB.GetNetClassName().c_str() ); + printf( "TrkA %p netclass '%s'\n", &trackA, (const char*) trackA.GetNetClassName().c_str() ); + printf( "TrkB %p netclass '%s'\n", &trackB, (const char*) trackB.GetNetClassName().c_str() ); -// testEvalExpr( "A.onlayer(\"F.Cu\") || A.onlayer(\"B.Cu\")", VAL(1.0), false, &trackA, &trackB ); - testEvalExpr( "A.type == \"Pad\" && B.type == \"Pad\" && (A.onLayer(\"F.Cu\"))",VAL(0.0), false, &trackA, &trackB ); +// testEvalExpr( "A.onlayer('F.Cu') || A.onlayer('B.Cu')", VAL( 1.0 ), false, &trackA, &trackB ); + testEvalExpr( "A.type == 'Pad' && B.type == 'Pad' && (A.onLayer('F.Cu'))", VAL( 0.0 ), false, &trackA, &trackB ); return 0; - testEvalExpr( "A.Width > B.Width", VAL(0.0), false, &trackA, &trackB ); - testEvalExpr( "A.Width + B.Width", VAL(Mils2iu(10) + Mils2iu(20)), false, &trackA, &trackB ); + testEvalExpr( "A.Width > B.Width", VAL( 0.0 ), false, &trackA, &trackB ); + testEvalExpr( "A.Width + B.Width", VAL( Mils2iu(10) + Mils2iu(20) ), false, &trackA, &trackB ); testEvalExpr( "A.Netclass", VAL( (const char*) trackA.GetNetClassName().c_str() ), false, &trackA, &trackB ); - testEvalExpr( "(A.Netclass == \"HV\") && (B.netclass == \"otherClass\") && (B.netclass != \"F.Cu\")", VAL( 1.0 ), false, &trackA, &trackB ); + testEvalExpr( "(A.Netclass == 'HV') && (B.netclass == 'otherClass') && (B.netclass != 'F.Cu')", VAL( 1.0 ), false, &trackA, &trackB ); testEvalExpr( "A.Netclass + 1.0", VAL( 1.0 ), false, &trackA, &trackB ); - testEvalExpr( "A.type == \"Track\" && B.type == \"Track\" && A.layer == \"F.Cu\"", VAL(0.0), false, &trackA, &trackB ); - testEvalExpr( "(A.type == \"Track\") && (B.type == \"Track\") && (A.layer == \"F.Cu\")", VAL(0.0), false, &trackA, &trackB ); + testEvalExpr( "A.type == 'Track' && B.type == 'Track' && A.layer == 'F.Cu'", VAL( 0.0 ), false, &trackA, &trackB ); + testEvalExpr( "(A.type == 'Track') && (B.type == 'Track') && (A.layer == 'F.Cu')", VAL( 0.0 ), false, &trackA, &trackB ); return 0; }