From 0f2ea5588cd6bfdec36b36ef8b6c643475797704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20David=20Mart=C3=ADnez=20M?= Date: Mon, 25 Aug 2025 14:52:42 -0500 Subject: [PATCH] [Core] Fix #15558: Direct expression in ternary operator (#22938) * [Core] Fix #15558: Direct expression in ternary operator * [Core] Added tests for Non-Numeric conditions in ternary op. * [Core] prevent relational operator chains at grammar level. * [Core] Rewrite expressions grammar as a layered grammar. * [Core] Revert to left associative relops (like C/C++) plus tests. --- src/App/Expression.cpp | 2 +- src/App/Expression.tab.c | 859 ++++++++++++------------- src/App/Expression.y | 27 +- src/App/ExpressionParser.sh | 2 +- src/Mod/Spreadsheet/TestSpreadsheet.py | 139 +++- 5 files changed, 565 insertions(+), 464 deletions(-) diff --git a/src/App/Expression.cpp b/src/App/Expression.cpp index f5a09e1e25..8f36832932 100644 --- a/src/App/Expression.cpp +++ b/src/App/Expression.cpp @@ -3264,7 +3264,7 @@ Expression *ConditionalExpression::simplify() const if (!v) return new ConditionalExpression(owner, condition->simplify(), trueExpr->simplify(), falseExpr->simplify()); else { - if (fabs(v->getValue()) > 0.5) + if (fabs(v->getValue()) >= Base::Precision::Confusion()) return trueExpr->simplify(); else return falseExpr->simplify(); diff --git a/src/App/Expression.tab.c b/src/App/Expression.tab.c index 20d6188fc1..d6602647d0 100644 --- a/src/App/Expression.tab.c +++ b/src/App/Expression.tab.c @@ -129,17 +129,17 @@ enum yysymbol_kind_t YYSYMBOL_DOCUMENT = 21, /* DOCUMENT */ YYSYMBOL_OBJECT = 22, /* OBJECT */ YYSYMBOL_EXPONENT = 23, /* EXPONENT */ - YYSYMBOL_24_ = 24, /* ':' */ - YYSYMBOL_25_ = 25, /* '+' */ - YYSYMBOL_26_ = 26, /* '*' */ - YYSYMBOL_27_ = 27, /* '/' */ - YYSYMBOL_28_ = 28, /* '%' */ - YYSYMBOL_NUM_AND_UNIT = 29, /* NUM_AND_UNIT */ - YYSYMBOL_30_ = 30, /* '^' */ - YYSYMBOL_NEG = 31, /* NEG */ - YYSYMBOL_POS = 32, /* POS */ - YYSYMBOL_33_ = 33, /* ')' */ - YYSYMBOL_34_ = 34, /* '?' */ + YYSYMBOL_24_ = 24, /* '?' */ + YYSYMBOL_25_ = 25, /* ':' */ + YYSYMBOL_26_ = 26, /* '+' */ + YYSYMBOL_27_ = 27, /* '*' */ + YYSYMBOL_28_ = 28, /* '/' */ + YYSYMBOL_29_ = 29, /* '%' */ + YYSYMBOL_NUM_AND_UNIT = 30, /* NUM_AND_UNIT */ + YYSYMBOL_31_ = 31, /* '^' */ + YYSYMBOL_NEG = 32, /* NEG */ + YYSYMBOL_POS = 33, /* POS */ + YYSYMBOL_34_ = 34, /* ')' */ YYSYMBOL_35_ = 35, /* '(' */ YYSYMBOL_36_ = 36, /* ',' */ YYSYMBOL_37_ = 37, /* ';' */ @@ -154,18 +154,17 @@ enum yysymbol_kind_t YYSYMBOL_num = 46, /* num */ YYSYMBOL_args = 47, /* args */ YYSYMBOL_range = 48, /* range */ - YYSYMBOL_cond = 49, /* cond */ - YYSYMBOL_us_building_unit = 50, /* us_building_unit */ - YYSYMBOL_other_unit = 51, /* other_unit */ - YYSYMBOL_unit_exp = 52, /* unit_exp */ - YYSYMBOL_integer = 53, /* integer */ - YYSYMBOL_id_or_cell = 54, /* id_or_cell */ - YYSYMBOL_identifier = 55, /* identifier */ - YYSYMBOL_iden = 56, /* iden */ - YYSYMBOL_indexer = 57, /* indexer */ - YYSYMBOL_indexable = 58, /* indexable */ - YYSYMBOL_document = 59, /* document */ - YYSYMBOL_object = 60 /* object */ + YYSYMBOL_us_building_unit = 49, /* us_building_unit */ + YYSYMBOL_other_unit = 50, /* other_unit */ + YYSYMBOL_unit_exp = 51, /* unit_exp */ + YYSYMBOL_integer = 52, /* integer */ + YYSYMBOL_id_or_cell = 53, /* id_or_cell */ + YYSYMBOL_identifier = 54, /* identifier */ + YYSYMBOL_iden = 55, /* iden */ + YYSYMBOL_indexer = 56, /* indexer */ + YYSYMBOL_indexable = 57, /* indexable */ + YYSYMBOL_document = 58, /* document */ + YYSYMBOL_object = 59 /* object */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; @@ -491,18 +490,18 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 43 +#define YYFINAL 40 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 409 +#define YYLAST 432 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 42 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 19 +#define YYNNTS 18 /* YYNRULES -- Number of rules. */ -#define YYNRULES 80 +#define YYNRULES 76 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 146 +#define YYNSTATES 140 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 281 @@ -522,13 +521,13 @@ static const yytype_int8 yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 39, 2, 28, 2, 2, - 35, 33, 26, 25, 36, 2, 38, 27, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 24, 37, - 2, 2, 2, 34, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 39, 2, 29, 2, 2, + 35, 34, 27, 26, 36, 2, 38, 28, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 25, 37, + 2, 2, 2, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 40, 2, 41, 30, 2, 2, 2, 2, 2, + 2, 40, 2, 41, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -546,8 +545,8 @@ static const yytype_int8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 29, - 31, 32 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 30, + 32, 33 }; #if YYDEBUG @@ -556,13 +555,12 @@ static const yytype_uint8 yyrline[] = { 0, 81, 81, 82, 85, 86, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 108, 109, 110, 111, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 124, 127, 128, 129, - 130, 131, 132, 133, 136, 137, 139, 140, 141, 142, - 143, 144, 145, 148, 149, 153, 154, 158, 159, 163, - 168, 173, 179, 186, 193, 200, 204, 205, 206, 207, - 208, 209, 210, 211, 215, 216, 217, 221, 222, 226, - 227 + 103, 104, 105, 106, 107, 108, 109, 110, 111, 114, + 115, 116, 117, 119, 120, 121, 122, 123, 124, 127, + 131, 132, 134, 135, 136, 137, 138, 139, 140, 143, + 144, 148, 149, 153, 154, 158, 163, 168, 174, 181, + 188, 195, 199, 200, 201, 202, 203, 204, 205, 206, + 210, 211, 212, 216, 217, 221, 222 }; #endif @@ -581,10 +579,10 @@ static const char *const yytname[] = "\"end of file\"", "error", "\"invalid token\"", "FUNC", "ONE", "NUM", "IDENTIFIER", "UNIT", "USUNIT", "INTEGER", "CONSTANT", "CELLADDRESS", "EQ", "NEQ", "LT", "GT", "GTE", "LTE", "STRING", "MINUSSIGN", - "PROPERTY_REF", "DOCUMENT", "OBJECT", "EXPONENT", "':'", "'+'", "'*'", - "'/'", "'%'", "NUM_AND_UNIT", "'^'", "NEG", "POS", "')'", "'?'", "'('", + "PROPERTY_REF", "DOCUMENT", "OBJECT", "EXPONENT", "'?'", "':'", "'+'", + "'*'", "'/'", "'%'", "NUM_AND_UNIT", "'^'", "NEG", "POS", "')'", "'('", "','", "';'", "'.'", "'#'", "'['", "']'", "$accept", "input", "unit_num", - "exp", "num", "args", "range", "cond", "us_building_unit", "other_unit", + "exp", "num", "args", "range", "us_building_unit", "other_unit", "unit_exp", "integer", "id_or_cell", "identifier", "iden", "indexer", "indexable", "document", "object", YY_NULLPTR }; @@ -596,12 +594,12 @@ yysymbol_name (yysymbol_kind_t yysymbol) } #endif -#define YYPACT_NINF (-34) +#define YYPACT_NINF (-32) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) -#define YYTABLE_NINF (-81) +#define YYTABLE_NINF (-77) #define yytable_value_is_error(Yyn) \ 0 @@ -610,21 +608,20 @@ yysymbol_name (yysymbol_kind_t yysymbol) STATE-NUM. */ static const yytype_int16 yypact[] = { - 106, 209, -34, -34, -33, -34, -34, -34, -34, -34, - 0, 209, 209, 106, 30, 28, -34, 379, -3, -16, - -34, -34, 129, 35, -5, 37, -13, 27, 55, 209, - 379, 70, -34, -16, -21, -34, -34, 357, 17, 131, - -34, 56, -34, -34, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 106, 209, 209, -3, 174, 26, 209, - -3, -3, 3, 163, -34, 63, 89, -34, 31, 46, - -34, 209, 209, 15, -34, -34, -34, 15, 379, 379, - 379, 379, 379, 379, 100, 100, 71, 71, 26, 71, - -34, 110, 121, 26, 26, -34, -34, 50, -34, 186, - 224, -34, -34, -34, -34, 81, 82, -34, 379, -34, - -16, 379, -34, -16, -34, -34, -34, 209, -34, 209, - 243, 5, -34, 47, 15, 72, 281, 209, -34, 209, - -34, 262, 83, -34, -34, -34, 300, 319, 209, -34, - 15, -34, -34, 338, -34, -34 + 100, 203, -32, -32, -31, -32, -32, -32, -32, -32, + 90, 203, 203, 100, 34, 17, -32, 401, 7, -32, + -32, 93, -10, -19, 19, 16, -5, 49, 203, 401, + 78, -32, -9, -32, -32, 358, -4, -32, 64, -32, + -32, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 100, 203, 203, 7, 84, 6, 7, 7, 3, + 156, -32, 107, 119, -32, 44, 52, -32, 203, 203, + 25, -32, -32, 25, 20, 20, 20, 20, 20, 20, + 68, 381, 68, 59, 59, 6, 59, -32, 122, 6, + 6, -32, -32, 57, -32, 167, 218, -32, -32, -32, + -32, 94, 96, -32, 401, -32, 401, -32, -32, -32, + 203, -32, -32, 203, 238, 0, -32, 80, 25, 401, + 278, 203, -32, 203, -32, 258, 98, -32, -32, -32, + 298, 318, 203, -32, 25, -32, -32, 338, -32, -32 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -632,35 +629,34 @@ static const yytype_int16 yypact[] = means the default is an error. */ static const yytype_int8 yydefact[] = { - 0, 0, 23, 24, 55, 45, 44, 25, 26, 56, - 8, 0, 0, 0, 0, 0, 7, 2, 6, 0, - 47, 46, 3, 57, 9, 58, 19, 0, 0, 0, - 27, 0, 28, 29, 57, 10, 11, 0, 0, 0, - 55, 0, 60, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 47, 4, 0, - 0, 0, 0, 0, 74, 0, 0, 75, 0, 0, - 20, 0, 0, 0, 22, 43, 52, 0, 37, 38, - 39, 40, 41, 42, 13, 12, 14, 15, 17, 16, - 18, 0, 0, 49, 48, 54, 53, 0, 50, 0, - 0, 65, 76, 79, 80, 0, 0, 62, 30, 32, - 34, 31, 33, 35, 36, 59, 5, 0, 51, 0, - 0, 0, 66, 0, 0, 21, 0, 0, 68, 0, - 67, 0, 0, 63, 61, 69, 0, 0, 0, 70, - 0, 72, 71, 0, 64, 73 + 0, 0, 29, 30, 51, 41, 40, 31, 32, 52, + 8, 0, 0, 0, 0, 0, 7, 2, 6, 43, + 42, 3, 53, 9, 54, 25, 0, 0, 0, 33, + 0, 34, 53, 10, 11, 0, 0, 51, 0, 56, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 43, 4, 0, 0, 0, + 0, 70, 0, 0, 71, 0, 0, 26, 0, 0, + 0, 28, 48, 0, 19, 20, 21, 22, 23, 24, + 13, 0, 12, 14, 15, 17, 16, 18, 0, 45, + 44, 50, 49, 0, 46, 0, 0, 61, 72, 75, + 76, 0, 0, 58, 35, 37, 36, 38, 39, 55, + 0, 5, 47, 0, 0, 0, 62, 0, 0, 27, + 0, 0, 64, 0, 63, 0, 0, 59, 57, 65, + 0, 0, 0, 66, 0, 68, 67, 0, 60, 69 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -34, -34, -34, 33, 51, -34, -11, 18, -17, -34, - 2, 32, -1, -34, -34, 116, -34, -34, 75 + -32, -32, -32, 32, 76, -32, 54, -17, -32, 2, + 46, -1, -32, -32, 112, -32, -32, 75 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - 0, 15, 16, 37, 18, 31, 32, 19, 20, 21, - 39, 98, 23, 24, 25, 64, 26, 27, 28 + 0, 15, 16, 35, 18, 30, 31, 19, 20, 36, + 94, 22, 23, 24, 61, 25, 26, 27 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -668,92 +664,98 @@ static const yytype_int8 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 34, 57, 22, 73, 5, 6, -78, 95, 1, 2, - 3, 4, 96, 42, 7, 8, 9, -80, 59, 33, - 58, 40, 97, 10, 11, 66, 9, 63, 43, 129, - 12, 38, 56, 17, 30, 63, 40, 40, -79, -77, - 29, 9, 9, 14, 35, 36, 130, 38, 41, 103, - 75, 59, 40, 40, 95, 88, 62, 9, 9, 96, - 109, 112, 93, 94, 106, 132, 68, 104, 107, 101, - 34, 34, 114, -80, 116, 65, 115, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 89, 90, 110, - 113, 50, 92, 69, 77, 102, 100, 51, 52, 53, - 54, 55, 55, 70, 108, 111, 71, 72, 91, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 6, 123, - 124, 140, 133, 134, 10, 11, 52, 53, 54, 118, - 55, 12, 120, 44, 45, 46, 47, 48, 49, 144, - 50, 13, 67, 105, 14, 117, 51, 52, 53, 54, - 125, 55, 126, 0, 131, 60, 61, 60, 61, 62, - 136, 62, 137, 0, 76, 0, 1, 2, 3, 4, - 0, 143, 7, 8, 9, 0, 0, 0, 2, 3, - 0, 10, 11, 7, 8, 0, 0, 99, 12, 1, - 2, 3, 4, 0, 0, 7, 8, 9, 29, 0, - 0, 14, 0, 0, 10, 11, 0, 0, 0, 0, - 119, 12, 1, 2, 3, 4, 0, 0, 7, 8, - 9, 29, 0, 0, 14, 0, 0, 10, 11, 0, - 0, 0, 0, 0, 12, 0, 44, 45, 46, 47, - 48, 49, 0, 50, 29, 0, 0, 14, 121, 51, - 52, 53, 54, 0, 55, 44, 45, 46, 47, 48, - 49, 0, 50, 0, 0, 122, 0, 127, 51, 52, - 53, 54, 0, 55, 44, 45, 46, 47, 48, 49, - 0, 50, 0, 0, 128, 0, 138, 51, 52, 53, - 54, 0, 55, 44, 45, 46, 47, 48, 49, 0, - 50, 0, 0, 139, 0, 0, 51, 52, 53, 54, - 0, 55, 44, 45, 46, 47, 48, 49, 0, 50, - 0, 0, 135, 0, 0, 51, 52, 53, 54, 0, - 55, 44, 45, 46, 47, 48, 49, 0, 50, 0, - 0, 141, 0, 0, 51, 52, 53, 54, 0, 55, - 44, 45, 46, 47, 48, 49, 0, 50, 0, 0, - 142, 0, 0, 51, 52, 53, 54, 0, 55, 44, - 45, 46, 47, 48, 49, 0, 50, 0, 0, 145, - 0, 0, 51, 52, 53, 54, 0, 55, 0, 0, - 74, 44, 45, 46, 47, 48, 49, 0, 50, 0, - 0, 0, 0, 0, 51, 52, 53, 54, 0, 55 + 32, 55, 21, 1, 2, 3, 4, 91, -74, 7, + 8, 9, 92, 39, 5, 6, 70, 40, 10, 11, + 56, 60, 93, 57, 58, 123, 12, 59, -76, -76, + 72, 37, 17, 29, 65, 28, 9, 59, 14, 47, + 37, 124, 54, 33, 34, 9, 49, 50, 51, 52, + 37, 53, 38, 85, 63, 9, 60, 62, 37, 89, + 90, 91, 99, 9, 100, 103, 92, 32, 32, 108, + 102, 111, 109, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 86, 87, 37, 66, 2, 3, + 53, 9, 96, 7, 8, 50, 51, 52, 126, 53, + 104, 106, 73, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 67, 97, 68, 69, 127, 128, 10, 11, + 57, 58, 105, 107, 59, 98, 12, 114, -75, -73, + 6, 88, 117, 138, 118, 13, 134, 64, 14, 112, + 101, 0, 119, 0, 0, 120, 0, 125, 0, 0, + 0, 0, 0, 130, 0, 131, 0, 0, 0, 1, + 2, 3, 4, 0, 137, 7, 8, 9, 0, 0, + 1, 2, 3, 4, 10, 11, 7, 8, 9, 0, + 0, 95, 12, 0, 0, 10, 11, 0, 0, 0, + 0, 28, 113, 12, 14, 0, 0, 0, 0, 0, + 0, 0, 28, 0, 0, 14, 1, 2, 3, 4, + 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, + 0, 10, 11, 0, 0, 0, 0, 0, 0, 12, + 41, 42, 43, 44, 45, 46, 0, 47, 28, 0, + 0, 14, 48, 115, 49, 50, 51, 52, 0, 53, + 41, 42, 43, 44, 45, 46, 0, 47, 0, 116, + 0, 0, 48, 121, 49, 50, 51, 52, 0, 53, + 41, 42, 43, 44, 45, 46, 0, 47, 0, 122, + 0, 0, 48, 132, 49, 50, 51, 52, 0, 53, + 41, 42, 43, 44, 45, 46, 0, 47, 0, 133, + 0, 0, 48, 0, 49, 50, 51, 52, 0, 53, + 41, 42, 43, 44, 45, 46, 0, 47, 0, 129, + 0, 0, 48, 0, 49, 50, 51, 52, 0, 53, + 41, 42, 43, 44, 45, 46, 0, 47, 0, 135, + 0, 0, 48, 0, 49, 50, 51, 52, 0, 53, + 41, 42, 43, 44, 45, 46, 0, 47, 0, 136, + 0, 0, 48, 0, 49, 50, 51, 52, 0, 53, + 41, 42, 43, 44, 45, 46, 0, 47, 0, 139, + 0, 0, 48, 0, 49, 50, 51, 52, 0, 53, + 0, 0, 71, 41, 42, 43, 44, 45, 46, 0, + 47, 0, 0, 0, 0, 48, 110, 49, 50, 51, + 52, 0, 53, 41, 42, 43, 44, 45, 46, 0, + 47, 0, 0, 0, 0, 48, 0, 49, 50, 51, + 52, 0, 53 }; static const yytype_int16 yycheck[] = { - 1, 18, 0, 24, 7, 8, 39, 4, 3, 4, - 5, 6, 9, 14, 9, 10, 11, 38, 34, 1, - 18, 6, 19, 18, 19, 38, 11, 40, 0, 24, - 25, 13, 35, 0, 1, 40, 6, 6, 38, 39, - 35, 11, 11, 38, 11, 12, 41, 29, 18, 18, - 33, 34, 6, 6, 4, 53, 30, 11, 11, 9, - 71, 72, 60, 61, 18, 18, 39, 68, 69, 6, - 71, 72, 73, 38, 91, 38, 77, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 71, - 72, 19, 59, 38, 38, 6, 63, 25, 26, 27, - 28, 30, 30, 33, 71, 72, 36, 37, 57, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 8, 38, - 38, 38, 123, 124, 18, 19, 26, 27, 28, 97, - 30, 25, 99, 12, 13, 14, 15, 16, 17, 140, - 19, 35, 26, 68, 38, 24, 25, 26, 27, 28, - 117, 30, 119, -1, 121, 26, 27, 26, 27, 30, - 127, 30, 129, -1, 33, -1, 3, 4, 5, 6, - -1, 138, 9, 10, 11, -1, -1, -1, 4, 5, - -1, 18, 19, 9, 10, -1, -1, 24, 25, 3, - 4, 5, 6, -1, -1, 9, 10, 11, 35, -1, - -1, 38, -1, -1, 18, 19, -1, -1, -1, -1, - 24, 25, 3, 4, 5, 6, -1, -1, 9, 10, - 11, 35, -1, -1, 38, -1, -1, 18, 19, -1, - -1, -1, -1, -1, 25, -1, 12, 13, 14, 15, - 16, 17, -1, 19, 35, -1, -1, 38, 24, 25, - 26, 27, 28, -1, 30, 12, 13, 14, 15, 16, - 17, -1, 19, -1, -1, 41, -1, 24, 25, 26, - 27, 28, -1, 30, 12, 13, 14, 15, 16, 17, - -1, 19, -1, -1, 41, -1, 24, 25, 26, 27, - 28, -1, 30, 12, 13, 14, 15, 16, 17, -1, - 19, -1, -1, 41, -1, -1, 25, 26, 27, 28, - -1, 30, 12, 13, 14, 15, 16, 17, -1, 19, - -1, -1, 41, -1, -1, 25, 26, 27, 28, -1, - 30, 12, 13, 14, 15, 16, 17, -1, 19, -1, - -1, 41, -1, -1, 25, 26, 27, 28, -1, 30, - 12, 13, 14, 15, 16, 17, -1, 19, -1, -1, - 41, -1, -1, 25, 26, 27, 28, -1, 30, 12, - 13, 14, 15, 16, 17, -1, 19, -1, -1, 41, - -1, -1, 25, 26, 27, 28, -1, 30, -1, -1, - 33, 12, 13, 14, 15, 16, 17, -1, 19, -1, - -1, -1, -1, -1, 25, 26, 27, 28, -1, 30 + 1, 18, 0, 3, 4, 5, 6, 4, 39, 9, + 10, 11, 9, 14, 7, 8, 25, 0, 18, 19, + 18, 40, 19, 27, 28, 25, 26, 31, 38, 38, + 34, 6, 0, 1, 39, 35, 11, 31, 38, 19, + 6, 41, 35, 11, 12, 11, 26, 27, 28, 29, + 6, 31, 18, 51, 38, 11, 40, 38, 6, 57, + 58, 4, 18, 11, 65, 66, 9, 68, 69, 70, + 18, 88, 73, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 6, 38, 4, 5, + 31, 11, 60, 9, 10, 27, 28, 29, 18, 31, + 68, 69, 38, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 34, 6, 36, 37, 117, 118, 18, 19, + 27, 28, 68, 69, 31, 6, 26, 95, 38, 39, + 8, 55, 38, 134, 38, 35, 38, 25, 38, 93, + 65, -1, 110, -1, -1, 113, -1, 115, -1, -1, + -1, -1, -1, 121, -1, 123, -1, -1, -1, 3, + 4, 5, 6, -1, 132, 9, 10, 11, -1, -1, + 3, 4, 5, 6, 18, 19, 9, 10, 11, -1, + -1, 25, 26, -1, -1, 18, 19, -1, -1, -1, + -1, 35, 25, 26, 38, -1, -1, -1, -1, -1, + -1, -1, 35, -1, -1, 38, 3, 4, 5, 6, + -1, -1, 9, 10, 11, -1, -1, -1, -1, -1, + -1, 18, 19, -1, -1, -1, -1, -1, -1, 26, + 12, 13, 14, 15, 16, 17, -1, 19, 35, -1, + -1, 38, 24, 25, 26, 27, 28, 29, -1, 31, + 12, 13, 14, 15, 16, 17, -1, 19, -1, 41, + -1, -1, 24, 25, 26, 27, 28, 29, -1, 31, + 12, 13, 14, 15, 16, 17, -1, 19, -1, 41, + -1, -1, 24, 25, 26, 27, 28, 29, -1, 31, + 12, 13, 14, 15, 16, 17, -1, 19, -1, 41, + -1, -1, 24, -1, 26, 27, 28, 29, -1, 31, + 12, 13, 14, 15, 16, 17, -1, 19, -1, 41, + -1, -1, 24, -1, 26, 27, 28, 29, -1, 31, + 12, 13, 14, 15, 16, 17, -1, 19, -1, 41, + -1, -1, 24, -1, 26, 27, 28, 29, -1, 31, + 12, 13, 14, 15, 16, 17, -1, 19, -1, 41, + -1, -1, 24, -1, 26, 27, 28, 29, -1, 31, + 12, 13, 14, 15, 16, 17, -1, 19, -1, 41, + -1, -1, 24, -1, 26, 27, 28, 29, -1, 31, + -1, -1, 34, 12, 13, 14, 15, 16, 17, -1, + 19, -1, -1, -1, -1, 24, 25, 26, 27, 28, + 29, -1, 31, 12, 13, 14, 15, 16, 17, -1, + 19, -1, -1, -1, -1, 24, -1, 26, 27, 28, + 29, -1, 31 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of @@ -761,20 +763,19 @@ static const yytype_int16 yycheck[] = static const yytype_int8 yystos[] = { 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 18, 19, 25, 35, 38, 43, 44, 45, 46, 49, - 50, 51, 52, 54, 55, 56, 58, 59, 60, 35, - 45, 47, 48, 49, 54, 45, 45, 45, 49, 52, - 6, 18, 54, 0, 12, 13, 14, 15, 16, 17, - 19, 25, 26, 27, 28, 30, 35, 50, 52, 34, - 26, 27, 30, 40, 57, 38, 38, 57, 39, 38, - 33, 36, 37, 24, 33, 33, 33, 38, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 52, 45, - 45, 46, 45, 52, 52, 4, 9, 19, 53, 24, - 45, 6, 6, 18, 54, 60, 18, 54, 45, 48, - 49, 45, 48, 49, 54, 54, 50, 24, 53, 24, - 45, 24, 41, 38, 38, 45, 45, 24, 41, 24, - 41, 45, 18, 54, 54, 41, 45, 45, 24, 41, - 38, 41, 41, 45, 54, 41 + 18, 19, 26, 35, 38, 43, 44, 45, 46, 49, + 50, 51, 53, 54, 55, 57, 58, 59, 35, 45, + 47, 48, 53, 45, 45, 45, 51, 6, 18, 53, + 0, 12, 13, 14, 15, 16, 17, 19, 24, 26, + 27, 28, 29, 31, 35, 49, 51, 27, 28, 31, + 40, 56, 38, 38, 56, 39, 38, 34, 36, 37, + 25, 34, 34, 38, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 51, 45, 45, 46, 51, + 51, 4, 9, 19, 52, 25, 45, 6, 6, 18, + 53, 59, 18, 53, 45, 48, 45, 48, 53, 53, + 25, 49, 52, 25, 45, 25, 41, 38, 38, 45, + 45, 25, 41, 25, 41, 45, 18, 53, 53, 41, + 45, 45, 25, 41, 38, 41, 41, 45, 53, 41 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ @@ -782,27 +783,25 @@ static const yytype_int8 yyr1[] = { 0, 42, 43, 43, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 48, 49, 49, 49, - 49, 49, 49, 49, 50, 51, 52, 52, 52, 52, - 52, 52, 52, 53, 53, 54, 54, 55, 55, 56, - 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, - 57, 57, 57, 57, 58, 58, 58, 59, 59, 60, - 60 + 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, + 46, 46, 46, 47, 47, 47, 47, 47, 47, 48, + 49, 50, 51, 51, 51, 51, 51, 51, 51, 52, + 52, 53, 53, 54, 54, 55, 55, 55, 55, 55, + 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, + 57, 57, 57, 58, 58, 59, 59 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 1, 1, 2, 4, 1, 1, 1, 1, - 2, 2, 3, 3, 3, 3, 3, 3, 3, 1, - 3, 5, 3, 1, 1, 1, 1, 1, 1, 1, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 1, 1, 1, 1, 3, 3, - 3, 4, 3, 1, 1, 1, 1, 1, 1, 4, - 2, 5, 3, 5, 7, 3, 3, 4, 4, 5, - 5, 6, 6, 7, 2, 2, 3, 1, 1, 1, - 1 + 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 1, 3, 5, 3, 1, + 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 3, 3, 3, 4, 3, 1, + 1, 1, 1, 1, 1, 4, 2, 5, 3, 5, + 7, 3, 3, 4, 4, 5, 5, 6, 6, 7, + 2, 2, 3, 1, 1, 1, 1 }; @@ -1008,49 +1007,43 @@ yydestruct (const char *yymsg, case YYSYMBOL_exp: /* exp */ #line 73 "Expression.y" { delete ((*yyvaluep).expr); } -#line 1011 "Expression.tab.c" +#line 1010 "Expression.tab.c" break; case YYSYMBOL_num: /* num */ #line 73 "Expression.y" { delete ((*yyvaluep).expr); } -#line 1017 "Expression.tab.c" +#line 1016 "Expression.tab.c" break; case YYSYMBOL_args: /* args */ #line 75 "Expression.y" { std::vector::const_iterator i = ((*yyvaluep).arguments).begin(); while (i != ((*yyvaluep).arguments).end()) { delete *i; ++i; } } -#line 1023 "Expression.tab.c" +#line 1022 "Expression.tab.c" break; case YYSYMBOL_range: /* range */ #line 73 "Expression.y" { delete ((*yyvaluep).expr); } -#line 1029 "Expression.tab.c" - break; - - case YYSYMBOL_cond: /* cond */ -#line 73 "Expression.y" - { delete ((*yyvaluep).expr); } -#line 1035 "Expression.tab.c" +#line 1028 "Expression.tab.c" break; case YYSYMBOL_unit_exp: /* unit_exp */ #line 73 "Expression.y" { delete ((*yyvaluep).expr); } -#line 1041 "Expression.tab.c" +#line 1034 "Expression.tab.c" break; case YYSYMBOL_indexer: /* indexer */ #line 74 "Expression.y" { delete ((*yyvaluep).component); } -#line 1047 "Expression.tab.c" +#line 1040 "Expression.tab.c" break; case YYSYMBOL_indexable: /* indexable */ #line 73 "Expression.y" { delete ((*yyvaluep).expr); } -#line 1053 "Expression.tab.c" +#line 1046 "Expression.tab.c" break; default: @@ -1320,378 +1313,354 @@ yyreduce: case 2: /* input: exp */ #line 81 "Expression.y" { ScanResult = (yyvsp[0].expr); valueExpression = true; } -#line 1323 "Expression.tab.c" +#line 1316 "Expression.tab.c" break; case 3: /* input: unit_exp */ #line 82 "Expression.y" { ScanResult = (yyvsp[0].expr); unitExpression = true; } -#line 1329 "Expression.tab.c" +#line 1322 "Expression.tab.c" break; case 4: /* unit_num: num unit_exp */ #line 85 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-1].expr), OperatorExpression::UNIT, (yyvsp[0].expr)); } -#line 1335 "Expression.tab.c" +#line 1328 "Expression.tab.c" break; case 5: /* unit_num: num us_building_unit num us_building_unit */ #line 86 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, new OperatorExpression(DocumentObject, (yyvsp[-3].expr), OperatorExpression::UNIT, (yyvsp[-2].expr)), OperatorExpression::ADD, new OperatorExpression(DocumentObject, (yyvsp[-1].expr), OperatorExpression::UNIT, (yyvsp[0].expr)));} -#line 1341 "Expression.tab.c" +#line 1334 "Expression.tab.c" break; case 6: /* exp: num */ #line 89 "Expression.y" { (yyval.expr) = (yyvsp[0].expr); } -#line 1347 "Expression.tab.c" +#line 1340 "Expression.tab.c" break; case 7: /* exp: unit_num */ #line 90 "Expression.y" { (yyval.expr) = (yyvsp[0].expr); } -#line 1353 "Expression.tab.c" +#line 1346 "Expression.tab.c" break; case 8: /* exp: STRING */ #line 91 "Expression.y" { (yyval.expr) = new StringExpression(DocumentObject, (yyvsp[0].string)); } -#line 1359 "Expression.tab.c" +#line 1352 "Expression.tab.c" break; case 9: /* exp: identifier */ #line 92 "Expression.y" { (yyval.expr) = new VariableExpression(DocumentObject, (yyvsp[0].path)); } -#line 1365 "Expression.tab.c" +#line 1358 "Expression.tab.c" break; case 10: /* exp: MINUSSIGN exp */ #line 93 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[0].expr), OperatorExpression::NEG, new NumberExpression(DocumentObject, Quantity(-1))); } -#line 1371 "Expression.tab.c" +#line 1364 "Expression.tab.c" break; case 11: /* exp: '+' exp */ #line 94 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[0].expr), OperatorExpression::POS, new NumberExpression(DocumentObject, Quantity(1))); } -#line 1377 "Expression.tab.c" +#line 1370 "Expression.tab.c" break; case 12: /* exp: exp '+' exp */ #line 95 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::ADD, (yyvsp[0].expr)); } -#line 1383 "Expression.tab.c" +#line 1376 "Expression.tab.c" break; case 13: /* exp: exp MINUSSIGN exp */ #line 96 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::SUB, (yyvsp[0].expr)); } -#line 1389 "Expression.tab.c" +#line 1382 "Expression.tab.c" break; case 14: /* exp: exp '*' exp */ #line 97 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::MUL, (yyvsp[0].expr)); } -#line 1395 "Expression.tab.c" +#line 1388 "Expression.tab.c" break; case 15: /* exp: exp '/' exp */ #line 98 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); } -#line 1401 "Expression.tab.c" +#line 1394 "Expression.tab.c" break; case 16: /* exp: exp '%' exp */ #line 99 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::MOD, (yyvsp[0].expr)); } -#line 1407 "Expression.tab.c" +#line 1400 "Expression.tab.c" break; case 17: /* exp: exp '/' unit_exp */ #line 100 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); } -#line 1413 "Expression.tab.c" +#line 1406 "Expression.tab.c" break; case 18: /* exp: exp '^' exp */ #line 101 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::POW, (yyvsp[0].expr)); } -#line 1419 "Expression.tab.c" +#line 1412 "Expression.tab.c" break; - case 19: /* exp: indexable */ + case 19: /* exp: exp EQ exp */ #line 102 "Expression.y" - { (yyval.expr) = (yyvsp[0].expr); } -#line 1425 "Expression.tab.c" + { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::EQ, (yyvsp[0].expr)); } +#line 1418 "Expression.tab.c" break; - case 20: /* exp: FUNC args ')' */ + case 20: /* exp: exp NEQ exp */ #line 103 "Expression.y" - { (yyval.expr) = new FunctionExpression(DocumentObject, (yyvsp[-2].func).first, std::move((yyvsp[-2].func).second), (yyvsp[-1].arguments));} -#line 1431 "Expression.tab.c" + { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::NEQ, (yyvsp[0].expr)); } +#line 1424 "Expression.tab.c" break; - case 21: /* exp: cond '?' exp ':' exp */ + case 21: /* exp: exp LT exp */ #line 104 "Expression.y" - { (yyval.expr) = new ConditionalExpression(DocumentObject, (yyvsp[-4].expr), (yyvsp[-2].expr), (yyvsp[0].expr)); } -#line 1437 "Expression.tab.c" + { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::LT, (yyvsp[0].expr)); } +#line 1430 "Expression.tab.c" break; - case 22: /* exp: '(' exp ')' */ + case 22: /* exp: exp GT exp */ #line 105 "Expression.y" - { (yyval.expr) = (yyvsp[-1].expr); } -#line 1443 "Expression.tab.c" + { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::GT, (yyvsp[0].expr)); } +#line 1436 "Expression.tab.c" break; - case 23: /* num: ONE */ + case 23: /* exp: exp GTE exp */ +#line 106 "Expression.y" + { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::GTE, (yyvsp[0].expr)); } +#line 1442 "Expression.tab.c" + break; + + case 24: /* exp: exp LTE exp */ +#line 107 "Expression.y" + { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::LTE, (yyvsp[0].expr)); } +#line 1448 "Expression.tab.c" + break; + + case 25: /* exp: indexable */ #line 108 "Expression.y" - { (yyval.expr) = new NumberExpression(DocumentObject, Quantity((yyvsp[0].fvalue))); } -#line 1449 "Expression.tab.c" + { (yyval.expr) = (yyvsp[0].expr); } +#line 1454 "Expression.tab.c" break; - case 24: /* num: NUM */ + case 26: /* exp: FUNC args ')' */ #line 109 "Expression.y" - { (yyval.expr) = new NumberExpression(DocumentObject, Quantity((yyvsp[0].fvalue))); } -#line 1455 "Expression.tab.c" + { (yyval.expr) = new FunctionExpression(DocumentObject, (yyvsp[-2].func).first, std::move((yyvsp[-2].func).second), (yyvsp[-1].arguments));} +#line 1460 "Expression.tab.c" break; - case 25: /* num: INTEGER */ + case 27: /* exp: exp '?' exp ':' exp */ #line 110 "Expression.y" - { (yyval.expr) = new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue))); } -#line 1461 "Expression.tab.c" + { (yyval.expr) = new ConditionalExpression(DocumentObject, (yyvsp[-4].expr), (yyvsp[-2].expr), (yyvsp[0].expr)); } +#line 1466 "Expression.tab.c" break; - case 26: /* num: CONSTANT */ + case 28: /* exp: '(' exp ')' */ #line 111 "Expression.y" - { (yyval.expr) = new ConstantExpression(DocumentObject, (yyvsp[0].constant).name, Quantity((yyvsp[0].constant).fvalue)); } -#line 1467 "Expression.tab.c" + { (yyval.expr) = (yyvsp[-1].expr); } +#line 1472 "Expression.tab.c" break; - case 27: /* args: exp */ -#line 113 "Expression.y" - { (yyval.arguments).push_back((yyvsp[0].expr)); } -#line 1473 "Expression.tab.c" - break; - - case 28: /* args: range */ + case 29: /* num: ONE */ #line 114 "Expression.y" - { (yyval.arguments).push_back((yyvsp[0].expr)); } -#line 1479 "Expression.tab.c" + { (yyval.expr) = new NumberExpression(DocumentObject, Quantity((yyvsp[0].fvalue))); } +#line 1478 "Expression.tab.c" break; - case 29: /* args: cond */ + case 30: /* num: NUM */ #line 115 "Expression.y" - { (yyval.arguments).push_back((yyvsp[0].expr)); } -#line 1485 "Expression.tab.c" + { (yyval.expr) = new NumberExpression(DocumentObject, Quantity((yyvsp[0].fvalue))); } +#line 1484 "Expression.tab.c" break; - case 30: /* args: args ',' exp */ + case 31: /* num: INTEGER */ #line 116 "Expression.y" - { (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); } -#line 1491 "Expression.tab.c" + { (yyval.expr) = new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue))); } +#line 1490 "Expression.tab.c" break; - case 31: /* args: args ';' exp */ + case 32: /* num: CONSTANT */ #line 117 "Expression.y" - { (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); } -#line 1497 "Expression.tab.c" + { (yyval.expr) = new ConstantExpression(DocumentObject, (yyvsp[0].constant).name, Quantity((yyvsp[0].constant).fvalue)); } +#line 1496 "Expression.tab.c" break; - case 32: /* args: args ',' range */ -#line 118 "Expression.y" - { (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); } -#line 1503 "Expression.tab.c" - break; - - case 33: /* args: args ';' range */ + case 33: /* args: exp */ #line 119 "Expression.y" - { (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); } -#line 1509 "Expression.tab.c" + { (yyval.arguments).push_back((yyvsp[0].expr)); } +#line 1502 "Expression.tab.c" break; - case 34: /* args: args ',' cond */ + case 34: /* args: range */ #line 120 "Expression.y" - { (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); } -#line 1515 "Expression.tab.c" + { (yyval.arguments).push_back((yyvsp[0].expr)); } +#line 1508 "Expression.tab.c" break; - case 35: /* args: args ';' cond */ + case 35: /* args: args ',' exp */ #line 121 "Expression.y" { (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); } -#line 1521 "Expression.tab.c" +#line 1514 "Expression.tab.c" break; - case 36: /* range: id_or_cell ':' id_or_cell */ + case 36: /* args: args ';' exp */ +#line 122 "Expression.y" + { (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); } +#line 1520 "Expression.tab.c" + break; + + case 37: /* args: args ',' range */ +#line 123 "Expression.y" + { (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); } +#line 1526 "Expression.tab.c" + break; + + case 38: /* args: args ';' range */ #line 124 "Expression.y" - { (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); } -#line 1527 "Expression.tab.c" + { (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); } +#line 1532 "Expression.tab.c" break; - case 37: /* cond: exp EQ exp */ + case 39: /* range: id_or_cell ':' id_or_cell */ #line 127 "Expression.y" - { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::EQ, (yyvsp[0].expr)); } -#line 1533 "Expression.tab.c" + { (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); } +#line 1538 "Expression.tab.c" break; - case 38: /* cond: exp NEQ exp */ -#line 128 "Expression.y" - { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::NEQ, (yyvsp[0].expr)); } -#line 1539 "Expression.tab.c" - break; - - case 39: /* cond: exp LT exp */ -#line 129 "Expression.y" - { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::LT, (yyvsp[0].expr)); } -#line 1545 "Expression.tab.c" - break; - - case 40: /* cond: exp GT exp */ -#line 130 "Expression.y" - { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::GT, (yyvsp[0].expr)); } -#line 1551 "Expression.tab.c" - break; - - case 41: /* cond: exp GTE exp */ + case 40: /* us_building_unit: USUNIT */ #line 131 "Expression.y" - { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::GTE, (yyvsp[0].expr)); } -#line 1557 "Expression.tab.c" + { (yyval.expr) = new UnitExpression(DocumentObject, (yyvsp[0].quantity).scaler, (yyvsp[0].quantity).unitStr ); } +#line 1544 "Expression.tab.c" break; - case 42: /* cond: exp LTE exp */ + case 41: /* other_unit: UNIT */ #line 132 "Expression.y" - { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::LTE, (yyvsp[0].expr)); } -#line 1563 "Expression.tab.c" + { (yyval.expr) = new UnitExpression(DocumentObject, (yyvsp[0].quantity).scaler, (yyvsp[0].quantity).unitStr ); } +#line 1550 "Expression.tab.c" break; - case 43: /* cond: '(' cond ')' */ -#line 133 "Expression.y" - { (yyval.expr) = (yyvsp[-1].expr); } -#line 1569 "Expression.tab.c" + case 42: /* unit_exp: other_unit */ +#line 134 "Expression.y" + { (yyval.expr) = (yyvsp[0].expr); } +#line 1556 "Expression.tab.c" break; - case 44: /* us_building_unit: USUNIT */ + case 43: /* unit_exp: us_building_unit */ +#line 135 "Expression.y" + { (yyval.expr) = (yyvsp[0].expr); } +#line 1562 "Expression.tab.c" + break; + + case 44: /* unit_exp: unit_exp '/' unit_exp */ #line 136 "Expression.y" - { (yyval.expr) = new UnitExpression(DocumentObject, (yyvsp[0].quantity).scaler, (yyvsp[0].quantity).unitStr ); } -#line 1575 "Expression.tab.c" - break; - - case 45: /* other_unit: UNIT */ -#line 137 "Expression.y" - { (yyval.expr) = new UnitExpression(DocumentObject, (yyvsp[0].quantity).scaler, (yyvsp[0].quantity).unitStr ); } -#line 1581 "Expression.tab.c" - break; - - case 46: /* unit_exp: other_unit */ -#line 139 "Expression.y" - { (yyval.expr) = (yyvsp[0].expr); } -#line 1587 "Expression.tab.c" - break; - - case 47: /* unit_exp: us_building_unit */ -#line 140 "Expression.y" - { (yyval.expr) = (yyvsp[0].expr); } -#line 1593 "Expression.tab.c" - break; - - case 48: /* unit_exp: unit_exp '/' unit_exp */ -#line 141 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); } -#line 1599 "Expression.tab.c" +#line 1568 "Expression.tab.c" break; - case 49: /* unit_exp: unit_exp '*' unit_exp */ -#line 142 "Expression.y" + case 45: /* unit_exp: unit_exp '*' unit_exp */ +#line 137 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::MUL, (yyvsp[0].expr)); } -#line 1605 "Expression.tab.c" +#line 1574 "Expression.tab.c" break; - case 50: /* unit_exp: unit_exp '^' integer */ -#line 143 "Expression.y" + case 46: /* unit_exp: unit_exp '^' integer */ +#line 138 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::POW, new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue)))); } -#line 1611 "Expression.tab.c" +#line 1580 "Expression.tab.c" break; - case 51: /* unit_exp: unit_exp '^' MINUSSIGN integer */ -#line 144 "Expression.y" + case 47: /* unit_exp: unit_exp '^' MINUSSIGN integer */ +#line 139 "Expression.y" { (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-3].expr), OperatorExpression::POW, new OperatorExpression(DocumentObject, new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue))), OperatorExpression::NEG, new NumberExpression(DocumentObject, Quantity(-1)))); } -#line 1617 "Expression.tab.c" +#line 1586 "Expression.tab.c" break; - case 52: /* unit_exp: '(' unit_exp ')' */ -#line 145 "Expression.y" + case 48: /* unit_exp: '(' unit_exp ')' */ +#line 140 "Expression.y" { (yyval.expr) = (yyvsp[-1].expr); } -#line 1623 "Expression.tab.c" +#line 1592 "Expression.tab.c" break; - case 53: /* integer: INTEGER */ -#line 148 "Expression.y" + case 49: /* integer: INTEGER */ +#line 143 "Expression.y" { (yyval.ivalue) = (yyvsp[0].ivalue); } -#line 1629 "Expression.tab.c" +#line 1598 "Expression.tab.c" break; - case 54: /* integer: ONE */ -#line 149 "Expression.y" + case 50: /* integer: ONE */ +#line 144 "Expression.y" { (yyval.ivalue) = (yyvsp[0].fvalue); } -#line 1635 "Expression.tab.c" +#line 1604 "Expression.tab.c" break; - case 55: /* id_or_cell: IDENTIFIER */ + case 51: /* id_or_cell: IDENTIFIER */ +#line 148 "Expression.y" + { (yyval.string) = std::move((yyvsp[0].string)); } +#line 1610 "Expression.tab.c" + break; + + case 52: /* id_or_cell: CELLADDRESS */ +#line 149 "Expression.y" + { (yyval.string) = std::move((yyvsp[0].string)); } +#line 1616 "Expression.tab.c" + break; + + case 53: /* identifier: id_or_cell */ #line 153 "Expression.y" - { (yyval.string) = std::move((yyvsp[0].string)); } -#line 1641 "Expression.tab.c" - break; - - case 56: /* id_or_cell: CELLADDRESS */ -#line 154 "Expression.y" - { (yyval.string) = std::move((yyvsp[0].string)); } -#line 1647 "Expression.tab.c" - break; - - case 57: /* identifier: id_or_cell */ -#line 158 "Expression.y" { (yyval.path) = ObjectIdentifier(DocumentObject); (yyval.path) << ObjectIdentifier::SimpleComponent((yyvsp[0].string)); } -#line 1653 "Expression.tab.c" +#line 1622 "Expression.tab.c" break; - case 58: /* identifier: iden */ -#line 159 "Expression.y" + case 54: /* identifier: iden */ +#line 154 "Expression.y" { (yyval.path) = std::move((yyvsp[0].path)); } -#line 1659 "Expression.tab.c" +#line 1628 "Expression.tab.c" break; - case 59: /* iden: '.' STRING '.' id_or_cell */ -#line 163 "Expression.y" + case 55: /* iden: '.' STRING '.' id_or_cell */ +#line 158 "Expression.y" { /* Path to property of a sub-object of the current object*/ (yyval.path) = ObjectIdentifier(DocumentObject,true); (yyval.path).setDocumentObjectName(DocumentObject,false,ObjectIdentifier::String(std::move((yyvsp[-2].string)),true),true); (yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); } -#line 1669 "Expression.tab.c" +#line 1638 "Expression.tab.c" break; - case 60: /* iden: '.' id_or_cell */ -#line 168 "Expression.y" + case 56: /* iden: '.' id_or_cell */ +#line 163 "Expression.y" { /* Path to property of the current document object */ (yyval.path) = ObjectIdentifier(DocumentObject,true); (yyval.path).setDocumentObjectName(DocumentObject); (yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); } -#line 1679 "Expression.tab.c" +#line 1648 "Expression.tab.c" break; - case 61: /* iden: object '.' STRING '.' id_or_cell */ -#line 173 "Expression.y" + case 57: /* iden: object '.' STRING '.' id_or_cell */ +#line 168 "Expression.y" { /* Path to property of a sub-object */ (yyval.path) = ObjectIdentifier(DocumentObject); (yyval.path).setDocumentObjectName(std::move((yyvsp[-4].string_or_identifier)), true, ObjectIdentifier::String(std::move((yyvsp[-2].string)),true),true); (yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); (yyval.path).resolveAmbiguity(); } -#line 1690 "Expression.tab.c" +#line 1659 "Expression.tab.c" break; - case 62: /* iden: object '.' id_or_cell */ -#line 179 "Expression.y" + case 58: /* iden: object '.' id_or_cell */ +#line 174 "Expression.y" { /* Path to property of a given document object */ (yyval.path) = ObjectIdentifier(DocumentObject); (yyvsp[-2].string_or_identifier).checkImport(DocumentObject); @@ -1699,11 +1668,11 @@ yyreduce: (yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); (yyval.path).resolveAmbiguity(); } -#line 1702 "Expression.tab.c" +#line 1671 "Expression.tab.c" break; - case 63: /* iden: document '#' object '.' id_or_cell */ -#line 186 "Expression.y" + case 59: /* iden: document '#' object '.' id_or_cell */ +#line 181 "Expression.y" { /* Path to property from an external document, within a named document object */ (yyval.path) = ObjectIdentifier(DocumentObject); (yyval.path).setDocumentName(std::move((yyvsp[-4].string_or_identifier)), true); @@ -1711,118 +1680,118 @@ yyreduce: (yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); (yyval.path).resolveAmbiguity(); } -#line 1714 "Expression.tab.c" +#line 1683 "Expression.tab.c" break; - case 64: /* iden: document '#' object '.' STRING '.' id_or_cell */ -#line 194 "Expression.y" + case 60: /* iden: document '#' object '.' STRING '.' id_or_cell */ +#line 189 "Expression.y" { (yyval.path) = ObjectIdentifier(DocumentObject); (yyval.path).setDocumentName(std::move((yyvsp[-6].string_or_identifier)), true); (yyval.path).setDocumentObjectName(std::move((yyvsp[-4].string_or_identifier)), true, ObjectIdentifier::String(std::move((yyvsp[-2].string)),true)); (yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); (yyval.path).resolveAmbiguity(); } -#line 1725 "Expression.tab.c" +#line 1694 "Expression.tab.c" break; - case 65: /* iden: iden '.' IDENTIFIER */ -#line 200 "Expression.y" + case 61: /* iden: iden '.' IDENTIFIER */ +#line 195 "Expression.y" { (yyval.path)= std::move((yyvsp[-2].path)); (yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); } -#line 1731 "Expression.tab.c" +#line 1700 "Expression.tab.c" break; - case 66: /* indexer: '[' exp ']' */ -#line 204 "Expression.y" + case 62: /* indexer: '[' exp ']' */ +#line 199 "Expression.y" { (yyval.component) = Expression::createComponent((yyvsp[-1].expr)); } -#line 1737 "Expression.tab.c" +#line 1706 "Expression.tab.c" break; - case 67: /* indexer: '[' exp ':' ']' */ -#line 205 "Expression.y" + case 63: /* indexer: '[' exp ':' ']' */ +#line 200 "Expression.y" { (yyval.component) = Expression::createComponent((yyvsp[-2].expr),0,0,true); } -#line 1743 "Expression.tab.c" +#line 1712 "Expression.tab.c" break; - case 68: /* indexer: '[' ':' exp ']' */ -#line 206 "Expression.y" + case 64: /* indexer: '[' ':' exp ']' */ +#line 201 "Expression.y" { (yyval.component) = Expression::createComponent(0,(yyvsp[-1].expr)); } -#line 1749 "Expression.tab.c" +#line 1718 "Expression.tab.c" break; - case 69: /* indexer: '[' ':' ':' exp ']' */ -#line 207 "Expression.y" + case 65: /* indexer: '[' ':' ':' exp ']' */ +#line 202 "Expression.y" { (yyval.component) = Expression::createComponent(0,0,(yyvsp[-1].expr)); } -#line 1755 "Expression.tab.c" +#line 1724 "Expression.tab.c" break; - case 70: /* indexer: '[' exp ':' exp ']' */ -#line 208 "Expression.y" + case 66: /* indexer: '[' exp ':' exp ']' */ +#line 203 "Expression.y" { (yyval.component) = Expression::createComponent((yyvsp[-3].expr),(yyvsp[-1].expr));} -#line 1761 "Expression.tab.c" +#line 1730 "Expression.tab.c" break; - case 71: /* indexer: '[' exp ':' ':' exp ']' */ -#line 209 "Expression.y" + case 67: /* indexer: '[' exp ':' ':' exp ']' */ +#line 204 "Expression.y" { (yyval.component) = Expression::createComponent((yyvsp[-4].expr),0,(yyvsp[-1].expr)); } -#line 1767 "Expression.tab.c" +#line 1736 "Expression.tab.c" break; - case 72: /* indexer: '[' ':' exp ':' exp ']' */ -#line 210 "Expression.y" + case 68: /* indexer: '[' ':' exp ':' exp ']' */ +#line 205 "Expression.y" { (yyval.component) = Expression::createComponent(0,(yyvsp[-3].expr),(yyvsp[-1].expr)); } -#line 1773 "Expression.tab.c" +#line 1742 "Expression.tab.c" break; - case 73: /* indexer: '[' exp ':' exp ':' exp ']' */ -#line 211 "Expression.y" + case 69: /* indexer: '[' exp ':' exp ':' exp ']' */ +#line 206 "Expression.y" { (yyval.component) = Expression::createComponent((yyvsp[-5].expr),(yyvsp[-3].expr),(yyvsp[-1].expr));} -#line 1779 "Expression.tab.c" +#line 1748 "Expression.tab.c" break; - case 74: /* indexable: identifier indexer */ -#line 215 "Expression.y" + case 70: /* indexable: identifier indexer */ +#line 210 "Expression.y" { (yyval.expr) = new VariableExpression(DocumentObject,(yyvsp[-1].path)); (yyval.expr)->addComponent((yyvsp[0].component)); } -#line 1785 "Expression.tab.c" +#line 1754 "Expression.tab.c" break; - case 75: /* indexable: indexable indexer */ -#line 216 "Expression.y" + case 71: /* indexable: indexable indexer */ +#line 211 "Expression.y" { (yyvsp[-1].expr)->addComponent(std::move((yyvsp[0].component))); (yyval.expr) = (yyvsp[-1].expr); } -#line 1791 "Expression.tab.c" +#line 1760 "Expression.tab.c" break; - case 76: /* indexable: indexable '.' IDENTIFIER */ -#line 217 "Expression.y" + case 72: /* indexable: indexable '.' IDENTIFIER */ +#line 212 "Expression.y" { (yyvsp[-2].expr)->addComponent(Expression::createComponent((yyvsp[0].string))); (yyval.expr) = (yyvsp[-2].expr); } -#line 1797 "Expression.tab.c" +#line 1766 "Expression.tab.c" break; - case 77: /* document: STRING */ + case 73: /* document: STRING */ +#line 216 "Expression.y" + { (yyval.string_or_identifier) = ObjectIdentifier::String(std::move((yyvsp[0].string)), true); } +#line 1772 "Expression.tab.c" + break; + + case 74: /* document: IDENTIFIER */ +#line 217 "Expression.y" + { (yyval.string_or_identifier) = ObjectIdentifier::String(std::move((yyvsp[0].string)), false, true);} +#line 1778 "Expression.tab.c" + break; + + case 75: /* object: STRING */ #line 221 "Expression.y" { (yyval.string_or_identifier) = ObjectIdentifier::String(std::move((yyvsp[0].string)), true); } -#line 1803 "Expression.tab.c" +#line 1784 "Expression.tab.c" break; - case 78: /* document: IDENTIFIER */ + case 76: /* object: id_or_cell */ #line 222 "Expression.y" - { (yyval.string_or_identifier) = ObjectIdentifier::String(std::move((yyvsp[0].string)), false, true);} -#line 1809 "Expression.tab.c" - break; - - case 79: /* object: STRING */ -#line 226 "Expression.y" - { (yyval.string_or_identifier) = ObjectIdentifier::String(std::move((yyvsp[0].string)), true); } -#line 1815 "Expression.tab.c" - break; - - case 80: /* object: id_or_cell */ -#line 227 "Expression.y" { (yyval.string_or_identifier) = ObjectIdentifier::String(std::move((yyvsp[0].string)), false);} -#line 1821 "Expression.tab.c" +#line 1790 "Expression.tab.c" break; -#line 1825 "Expression.tab.c" +#line 1794 "Expression.tab.c" default: break; } @@ -2015,5 +1984,5 @@ yyreturnlab: return yyresult; } -#line 230 "Expression.y" +#line 225 "Expression.y" diff --git a/src/App/Expression.y b/src/App/Expression.y index d88be0d2c7..4ce11fc82e 100644 --- a/src/App/Expression.y +++ b/src/App/Expression.y @@ -45,7 +45,7 @@ std::stack functions; /**< Function %token DOCUMENT OBJECT %token EXPONENT %type args - %type input unit_num us_building_unit other_unit exp unit_exp cond indexable + %type input unit_num us_building_unit other_unit exp unit_exp indexable %type UNIT USUNIT %type id_or_cell STRING IDENTIFIER CELLADDRESS %type INTEGER @@ -61,8 +61,8 @@ std::stack functions; /**< Function %type document %type object %type integer - %precedence EQ NEQ LT GT GTE LTE - %precedence ':' + %right '?' ':' + %left EQ NEQ LT GT GTE LTE %left MINUSSIGN '+' %left '*' '/' '%' %precedence NUM_AND_UNIT @@ -70,7 +70,7 @@ std::stack functions; /**< Function %precedence NEG %precedence POS -%destructor { delete $$; } num range exp cond unit_exp indexable +%destructor { delete $$; } num range exp unit_exp indexable %destructor { delete $$; } %destructor { std::vector::const_iterator i = $$.begin(); while (i != $$.end()) { delete *i; ++i; } } args @@ -99,9 +99,15 @@ exp: num { $$ = $1; | exp '%' exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::MOD, $3); } | exp '/' unit_exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::DIV, $3); } | exp '^' exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, $3); } + | exp EQ exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::EQ, $3); } + | exp NEQ exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::NEQ, $3); } + | exp LT exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::LT, $3); } + | exp GT exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::GT, $3); } + | exp GTE exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::GTE, $3); } + | exp LTE exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::LTE, $3); } | indexable { $$ = $1; } | FUNC args ')' { $$ = new FunctionExpression(DocumentObject, $1.first, std::move($1.second), $2);} - | cond '?' exp ':' exp { $$ = new ConditionalExpression(DocumentObject, $1, $3, $5); } + | exp '?' exp ':' exp { $$ = new ConditionalExpression(DocumentObject, $1, $3, $5); } | '(' exp ')' { $$ = $2; } ; @@ -112,26 +118,15 @@ num: ONE { $$ = new NumberExpression(Docu args: exp { $$.push_back($1); } | range { $$.push_back($1); } - | cond { $$.push_back($1); } | args ',' exp { $1.push_back($3); $$ = $1; } | args ';' exp { $1.push_back($3); $$ = $1; } | args ',' range { $1.push_back($3); $$ = $1; } | args ';' range { $1.push_back($3); $$ = $1; } - | args ',' cond { $1.push_back($3); $$ = $1; } - | args ';' cond { $1.push_back($3); $$ = $1; } ; range: id_or_cell ':' id_or_cell { $$ = new RangeExpression(DocumentObject, $1, $3); } ; -cond: exp EQ exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::EQ, $3); } - | exp NEQ exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::NEQ, $3); } - | exp LT exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::LT, $3); } - | exp GT exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::GT, $3); } - | exp GTE exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::GTE, $3); } - | exp LTE exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::LTE, $3); } - | '(' cond ')' { $$ = $2; } - ; us_building_unit: USUNIT { $$ = new UnitExpression(DocumentObject, $1.scaler, $1.unitStr ); } other_unit: UNIT { $$ = new UnitExpression(DocumentObject, $1.scaler, $1.unitStr ); } diff --git a/src/App/ExpressionParser.sh b/src/App/ExpressionParser.sh index dfa85af868..26acc673c2 100755 --- a/src/App/ExpressionParser.sh +++ b/src/App/ExpressionParser.sh @@ -2,7 +2,7 @@ (cd "$(dirname "$0")" && \ flex -v -oExpression.lex.c Expression.l && \ - bison -d -v -Wall -oExpression.tab.c Expression.y && \ + bison -d -v -Wall -oExpression.tab.c -Wcounterexamples -Wconflicts-sr Expression.y && \ sed -i '1s|^|// clang-format off\n|' Expression.tab.c && \ sed -i '1s|^|// clang-format off\n|' Expression.lex.c \ ) diff --git a/src/Mod/Spreadsheet/TestSpreadsheet.py b/src/Mod/Spreadsheet/TestSpreadsheet.py index 961de5f282..cd52dfcb8f 100644 --- a/src/Mod/Spreadsheet/TestSpreadsheet.py +++ b/src/Mod/Spreadsheet/TestSpreadsheet.py @@ -20,7 +20,6 @@ # ***************************************************************************/ import os -import sys import math from math import sqrt import unittest @@ -949,6 +948,48 @@ class SpreadsheetCases(unittest.TestCase): self.assertEqual(sheet.getContents("A51"), "=+(-1 + 1)") self.assertEqual(sheet.getContents("A52"), "=+(-1 + -1)") + # More ternary operator precedence tests + sheet.set("X1", "1") + sheet.set("X2", "10") + sheet.set("X3", "100") + sheet.set("X4", "1000") + sheet.set("Y1", "= X1 ? 0 : 1 ? X2 ? 2 : 3 : X3 ? 4 : 5") + sheet.set("Y2", "= X1 + X2 ? X3 - 2 : 3 + X4") + + self.doc.recompute() + self.assertEqual(sheet.getContents("Y1"), "=X1 ? 0 : (1 ? (X2 ? 2 : 3) : (X3 ? 4 : 5))") + self.assertEqual(sheet.Y2, 98) + + def testImplicitRelOpChains(self): + """Test implicit chains of relational operators""" + sheet = self.doc.addObject("Spreadsheet::Sheet", "Spreadsheet") + + def check(implicit: str, explicit: str): + sheet.set("Z1", implicit) + sheet.set("Z2", explicit) + self.doc.recompute() + self.assertEqual(sheet.getContents("Z2"), sheet.getContents("Z1")) + + check("=1 < 2 < 3 ? 3 : 4", "=(1 < 2) < 3 ? 3 : 4") + check("=1 < 2 < 3 < 4 ? 3 : 4", "=((1 < 2) < 3) < 4 ? 3 : 4") + check("=A1 < B1 < 3 ? 3 : 4", "=(A1 < B1) < 3 ? 3 : 4") + check("=1 < C1 < D2 ? 3 : 4", "=(1 < C1) < D2 ? 3 : 4") + check("=X1 < B1 < D1 < 0 ? 3 : 4", "=((X1 < B1) < D1) < 0 ? 3 : 4") + + def testExplicitRelOpChaining(self): + """Testing explicit relational operators chaining.""" + sheet = self.doc.addObject("Spreadsheet::Sheet", "Spreadsheet") + + sheet.set("X1", "= (1 < 2) == (2 < 3)") + sheet.set("X2", "= (1 < 2) == (2 > 3)") + sheet.set("X3", "= (1 < 2) == 1") + sheet.set("X4", "= 0 == (1 > 2)") + self.doc.recompute() + self.assertTrue(sheet.get("X1")) + self.assertFalse(sheet.get("X2")) + self.assertTrue(sheet.get("X3")) + self.assertTrue(sheet.get("X4")) + def testNumbers(self): """Test different numbers""" sheet = self.doc.addObject("Spreadsheet::Sheet", "Spreadsheet") @@ -1879,3 +1920,99 @@ class SpreadsheetCases(unittest.TestCase): self.assertLess(sheet.F3.distanceToPoint(FreeCAD.Vector(0.28, 0.04, -0.2)), tolerance) self.assertLess(abs(sheet.F4.Value - -1.6971), 0.0001) self.assertEqual(sheet.F5, FreeCAD.Vector(1.72, 2.96, 4.2)) + + def testTernaryOperator(self): + """Testing ternary operator""" + sheet = self.doc.addObject("Spreadsheet::Sheet", "Spreadsheet") + sheet.set("A1", "= 1 ? 10 : 20") + sheet.set("A2", "= 0 ? 10 : 20") + sheet.set("A3", "= True ? 10 : 20") + sheet.set("A4", "= False ? 10 : 20") + sheet.set("B1", "= 1mm ? 10 : 20") + sheet.set("B2", "= 0mm ? 10 : 20") + sheet.set("C1", "= 2 == 2 ? 10 : 20") + sheet.set("C2", "= 2 != 2 ? 10 : 20") + sheet.set("C3", "= 2 > 1 ? 10 : 20") + sheet.set("C4", "= 1 > 2 ? 10 : 20") + + sheet.set("D1", "= and(1 < 2, 3 < 4) ? 10 : 20") + sheet.set("D2", "= and(1 < 2, 3 > 4) ? 10 : 20") + sheet.set("D3", "= and(1 > 2, 3 < 4) ? 10 : 20") + sheet.set("D4", "= and(1 > 2, 3 > 4) ? 10 : 20") + + sheet.set("E1", "= or(1 < 2, 3 < 4) ? 10 : 20") + sheet.set("E2", "= or(1 < 2, 3 > 4) ? 10 : 20") + sheet.set("E3", "= or(1 > 2, 3 < 4) ? 10 : 20") + sheet.set("E4", "= or(1 > 2, 3 > 4) ? 10 : 20") + + sheet.set("F1", "= not(2 > 1) ? 10 : 20") + sheet.set("F2", "= not(2 < 1) ? 10 : 20") + + sheet.addProperty("App::PropertyBool", "PropTrue", "", "") + sheet.PropTrue = True + sheet.addProperty("App::PropertyBool", "PropFalse", "", "") + sheet.PropFalse = False + sheet.addProperty("App::PropertyLength", "PropL", "", "") + sheet.PropL = "0 mm" + sheet.addProperty("App::PropertyLength", "PropH", "", "") + sheet.PropH = "5 mm" + sheet.addProperty("App::PropertyInteger", "PropI", "", "") + sheet.PropI = -5 + sheet.addProperty("App::PropertyString", "PropS", "", "") + sheet.PropS = "This is a test" + sheet.addProperty("App::PropertyString", "PropSEmpty", "", "") + + sheet.set("G1", "= Spreadsheet.PropTrue ? 10 : 20") + sheet.set("G2", "= Spreadsheet.PropFalse ? 10 : 20") + sheet.set("G3", "= Spreadsheet.PropL ? 10 : 20") + sheet.set("G4", "= Spreadsheet.PropH ? 10 : 20") + sheet.set("G5", "= Spreadsheet.PropI ? 10 : 20") + sheet.set("G6", "= Spreadsheet.PropS ? 10 : 20") + sheet.set("G7", "= Spreadsheet.PropSEmpty ? 10 : 20") + sheet.set("G8", "= <> ? 10 : 20") + sheet.set("G9", "= <<>> ? 10 : 20") + sheet.set("G10", "= <> ? 10 : 20") + + self.doc.recompute() + + # Constants + self.assertEqual(sheet.get("A1"), 10) + self.assertEqual(sheet.get("A2"), 20) + self.assertEqual(sheet.get("A3"), 10) + self.assertEqual(sheet.get("A4"), 20) + + # Constant Quantities + self.assertEqual(sheet.get("B1"), 10) + self.assertEqual(sheet.get("B2"), 20) + + # Basic Comparisons + self.assertEqual(sheet.get("C1"), 10) + self.assertEqual(sheet.get("C2"), 20) + self.assertEqual(sheet.get("C3"), 10) + self.assertEqual(sheet.get("C4"), 20) + + # Function calls + self.assertEqual(sheet.get("D1"), 10) + self.assertEqual(sheet.get("D2"), 20) + self.assertEqual(sheet.get("D3"), 20) + self.assertEqual(sheet.get("D4"), 20) + self.assertEqual(sheet.get("E1"), 10) + self.assertEqual(sheet.get("E2"), 10) + self.assertEqual(sheet.get("E3"), 10) + self.assertEqual(sheet.get("E4"), 20) + self.assertEqual(sheet.get("F1"), 20) + self.assertEqual(sheet.get("F2"), 10) + + # Property lookup + self.assertEqual(sheet.get("G1"), 10) + self.assertEqual(sheet.get("G2"), 20) + self.assertEqual(sheet.get("G3"), 20) + self.assertEqual(sheet.get("G4"), 10) + self.assertEqual(sheet.get("G5"), 10) + + # Non numeric conditions + self.assertEqual(sheet.get("G6"), 10) + self.assertEqual(sheet.get("G7"), 20) + self.assertEqual(sheet.get("G8"), 10) + self.assertEqual(sheet.get("G9"), 20) + self.assertEqual(sheet.get("G10"), 10)