From bc8418dda102502769ae083cc3b2b23e58b89820 Mon Sep 17 00:00:00 2001 From: David Hugh-Jones Date: Sun, 7 Dec 2025 08:05:19 +0000 Subject: [PATCH 1/2] Add pipe assignment operator <|> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LHS <|> RHS is parsed as LHS <- RHS(LHS, ...). Example: x <|> sqrt() # becomes x <- sqrt(x) names(x) <|> toupper() # becomes names(x) <- toupper(names(x)) x <|> gsub("pattern", "replacement", x = _) # becomes x <- gsub("pattern", "replacement", x = x) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/main/gram.c | 729 +++++++++++++++++++--------------- src/main/gram.y | 73 +++- tests/reg-tests-pipe-assign.R | 102 +++++ 3 files changed, 584 insertions(+), 320 deletions(-) create mode 100644 tests/reg-tests-pipe-assign.R diff --git a/src/main/gram.c b/src/main/gram.c index b0355d6e420..97d5f46182f 100644 --- a/src/main/gram.c +++ b/src/main/gram.c @@ -453,6 +453,7 @@ static SEXP xxfuncall(SEXP, SEXP); static SEXP xxdefun(SEXP, SEXP, SEXP, YYLTYPE *); static SEXP xxpipe(SEXP, SEXP, YYLTYPE *); static SEXP xxpipebind(SEXP, SEXP, SEXP, YYLTYPE *); +static SEXP xxpipeassign(SEXP, SEXP, YYLTYPE *, YYLTYPE *); static SEXP xxunary(SEXP, SEXP); static SEXP xxbinary(SEXP, SEXP, SEXP); static SEXP xxparen(SEXP, SEXP); @@ -547,13 +548,14 @@ extern int yydebug; PIPE = 299, /* PIPE */ PLACEHOLDER = 300, /* PLACEHOLDER */ PIPEBIND = 301, /* PIPEBIND */ - LOW = 302, /* LOW */ - TILDE = 303, /* TILDE */ - UNOT = 304, /* UNOT */ - NOT = 305, /* NOT */ - SPECIAL = 306, /* SPECIAL */ - UMINUS = 307, /* UMINUS */ - UPLUS = 308 /* UPLUS */ + PIPE_ASSIGN = 302, /* PIPE_ASSIGN */ + LOW = 303, /* LOW */ + TILDE = 304, /* TILDE */ + UNOT = 305, /* UNOT */ + NOT = 306, /* NOT */ + SPECIAL = 307, /* SPECIAL */ + UMINUS = 308, /* UMINUS */ + UPLUS = 309 /* UPLUS */ }; typedef enum yytokentype yytoken_kind_t; #endif @@ -606,13 +608,14 @@ extern int yydebug; #define PIPE 299 #define PLACEHOLDER 300 #define PIPEBIND 301 -#define LOW 302 -#define TILDE 303 -#define UNOT 304 -#define NOT 305 -#define SPECIAL 306 -#define UMINUS 307 -#define UPLUS 308 +#define PIPE_ASSIGN 302 +#define LOW 303 +#define TILDE 304 +#define UNOT 305 +#define NOT 306 +#define SPECIAL 307 +#define UMINUS 308 +#define UPLUS 309 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED @@ -694,47 +697,48 @@ enum yysymbol_kind_t YYSYMBOL_PIPE = 44, /* PIPE */ YYSYMBOL_PLACEHOLDER = 45, /* PLACEHOLDER */ YYSYMBOL_PIPEBIND = 46, /* PIPEBIND */ - YYSYMBOL_47_ = 47, /* '?' */ - YYSYMBOL_LOW = 48, /* LOW */ - YYSYMBOL_49_ = 49, /* '~' */ - YYSYMBOL_TILDE = 50, /* TILDE */ - YYSYMBOL_UNOT = 51, /* UNOT */ - YYSYMBOL_NOT = 52, /* NOT */ - YYSYMBOL_53_ = 53, /* '+' */ - YYSYMBOL_54_ = 54, /* '-' */ - YYSYMBOL_55_ = 55, /* '*' */ - YYSYMBOL_56_ = 56, /* '/' */ - YYSYMBOL_SPECIAL = 57, /* SPECIAL */ - YYSYMBOL_58_ = 58, /* ':' */ - YYSYMBOL_UMINUS = 59, /* UMINUS */ - YYSYMBOL_UPLUS = 60, /* UPLUS */ - YYSYMBOL_61_ = 61, /* '^' */ - YYSYMBOL_62_ = 62, /* '$' */ - YYSYMBOL_63_ = 63, /* '@' */ - YYSYMBOL_64_ = 64, /* '(' */ - YYSYMBOL_65_ = 65, /* '[' */ - YYSYMBOL_66_n_ = 66, /* '\n' */ - YYSYMBOL_67_ = 67, /* ';' */ - YYSYMBOL_68_ = 68, /* '{' */ - YYSYMBOL_69_ = 69, /* '}' */ - YYSYMBOL_70_ = 70, /* ')' */ - YYSYMBOL_71_ = 71, /* '!' */ - YYSYMBOL_72_ = 72, /* '\\' */ - YYSYMBOL_73_ = 73, /* ']' */ - YYSYMBOL_74_ = 74, /* ',' */ - YYSYMBOL_YYACCEPT = 75, /* $accept */ - YYSYMBOL_prog = 76, /* prog */ - YYSYMBOL_expr_or_assign_or_help = 77, /* expr_or_assign_or_help */ - YYSYMBOL_expr_or_help = 78, /* expr_or_help */ - YYSYMBOL_expr = 79, /* expr */ - YYSYMBOL_cond = 80, /* cond */ - YYSYMBOL_ifcond = 81, /* ifcond */ - YYSYMBOL_forcond = 82, /* forcond */ - YYSYMBOL_exprlist = 83, /* exprlist */ - YYSYMBOL_sublist = 84, /* sublist */ - YYSYMBOL_sub = 85, /* sub */ - YYSYMBOL_formlist = 86, /* formlist */ - YYSYMBOL_cr = 87 /* cr */ + YYSYMBOL_PIPE_ASSIGN = 47, /* PIPE_ASSIGN */ + YYSYMBOL_48_ = 48, /* '?' */ + YYSYMBOL_LOW = 49, /* LOW */ + YYSYMBOL_50_ = 50, /* '~' */ + YYSYMBOL_TILDE = 51, /* TILDE */ + YYSYMBOL_UNOT = 52, /* UNOT */ + YYSYMBOL_NOT = 53, /* NOT */ + YYSYMBOL_54_ = 54, /* '+' */ + YYSYMBOL_55_ = 55, /* '-' */ + YYSYMBOL_56_ = 56, /* '*' */ + YYSYMBOL_57_ = 57, /* '/' */ + YYSYMBOL_SPECIAL = 58, /* SPECIAL */ + YYSYMBOL_59_ = 59, /* ':' */ + YYSYMBOL_UMINUS = 60, /* UMINUS */ + YYSYMBOL_UPLUS = 61, /* UPLUS */ + YYSYMBOL_62_ = 62, /* '^' */ + YYSYMBOL_63_ = 63, /* '$' */ + YYSYMBOL_64_ = 64, /* '@' */ + YYSYMBOL_65_ = 65, /* '(' */ + YYSYMBOL_66_ = 66, /* '[' */ + YYSYMBOL_67_n_ = 67, /* '\n' */ + YYSYMBOL_68_ = 68, /* ';' */ + YYSYMBOL_69_ = 69, /* '{' */ + YYSYMBOL_70_ = 70, /* '}' */ + YYSYMBOL_71_ = 71, /* ')' */ + YYSYMBOL_72_ = 72, /* '!' */ + YYSYMBOL_73_ = 73, /* '\\' */ + YYSYMBOL_74_ = 74, /* ']' */ + YYSYMBOL_75_ = 75, /* ',' */ + YYSYMBOL_YYACCEPT = 76, /* $accept */ + YYSYMBOL_prog = 77, /* prog */ + YYSYMBOL_expr_or_assign_or_help = 78, /* expr_or_assign_or_help */ + YYSYMBOL_expr_or_help = 79, /* expr_or_help */ + YYSYMBOL_expr = 80, /* expr */ + YYSYMBOL_cond = 81, /* cond */ + YYSYMBOL_ifcond = 82, /* ifcond */ + YYSYMBOL_forcond = 83, /* forcond */ + YYSYMBOL_exprlist = 84, /* exprlist */ + YYSYMBOL_sublist = 85, /* sublist */ + YYSYMBOL_sub = 86, /* sub */ + YYSYMBOL_formlist = 87, /* formlist */ + YYSYMBOL_cr = 88 /* cr */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; @@ -1065,19 +1069,19 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 48 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 572 +#define YYLAST 655 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 75 +#define YYNTOKENS 76 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 13 /* YYNRULES -- Number of rules. */ -#define YYNRULES 94 +#define YYNRULES 95 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 174 +#define YYNSTATES 176 /* YYMAXUTOK -- Last valid token kind. */ -#define YYMAXUTOK 308 +#define YYMAXUTOK 309 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM @@ -1092,18 +1096,18 @@ union yyalloc static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 66, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 67, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 71, 2, 2, 62, 2, 2, 2, - 64, 70, 55, 53, 74, 54, 2, 56, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 58, 67, - 2, 2, 2, 47, 63, 2, 2, 2, 2, 2, + 2, 2, 2, 72, 2, 2, 63, 2, 2, 2, + 65, 71, 56, 54, 75, 55, 2, 57, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 59, 68, + 2, 2, 2, 48, 64, 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, 65, 72, 73, 61, 2, 2, 2, 2, 2, + 2, 66, 73, 74, 62, 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, 68, 2, 69, 49, 2, 2, 2, + 2, 2, 2, 69, 2, 70, 50, 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, @@ -1121,23 +1125,23 @@ static const yytype_int8 yytranslate[] = 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 48, 50, 51, 52, 57, 59, 60 + 45, 46, 47, 49, 51, 52, 53, 58, 60, 61 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { - 0, 446, 446, 447, 448, 449, 450, 453, 454, 455, - 458, 459, 462, 463, 464, 465, 466, 468, 469, 471, - 472, 473, 474, 475, 477, 478, 479, 480, 481, 482, - 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 501, 502, 503, - 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, - 527, 530, 533, 537, 538, 539, 540, 541, 542, 545, - 546, 549, 550, 551, 552, 553, 554, 555, 556, 559, - 560, 561, 562, 563, 567 + 0, 449, 449, 450, 451, 452, 453, 456, 457, 458, + 461, 462, 465, 466, 467, 468, 469, 471, 472, 474, + 475, 476, 477, 478, 480, 481, 482, 483, 484, 485, + 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, 502, 503, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, + 527, 531, 534, 537, 541, 542, 543, 544, 545, 546, + 549, 550, 553, 554, 555, 556, 557, 558, 559, 560, + 563, 564, 565, 566, 567, 571 }; #endif @@ -1160,13 +1164,13 @@ static const char *const yytname[] = "GE", "LT", "LE", "EQ", "NE", "AND", "OR", "AND2", "OR2", "NS_GET", "NS_GET_INT", "COMMENT", "LINE_DIRECTIVE", "SYMBOL_FORMALS", "EQ_FORMALS", "EQ_SUB", "SYMBOL_SUB", "SYMBOL_FUNCTION_CALL", - "SYMBOL_PACKAGE", "SLOT", "PIPE", "PLACEHOLDER", "PIPEBIND", "'?'", - "LOW", "'~'", "TILDE", "UNOT", "NOT", "'+'", "'-'", "'*'", "'/'", - "SPECIAL", "':'", "UMINUS", "UPLUS", "'^'", "'$'", "'@'", "'('", "'['", - "'\\n'", "';'", "'{'", "'}'", "')'", "'!'", "'\\\\'", "']'", "','", - "$accept", "prog", "expr_or_assign_or_help", "expr_or_help", "expr", - "cond", "ifcond", "forcond", "exprlist", "sublist", "sub", "formlist", - "cr", YY_NULLPTR + "SYMBOL_PACKAGE", "SLOT", "PIPE", "PLACEHOLDER", "PIPEBIND", + "PIPE_ASSIGN", "'?'", "LOW", "'~'", "TILDE", "UNOT", "NOT", "'+'", "'-'", + "'*'", "'/'", "SPECIAL", "':'", "UMINUS", "UPLUS", "'^'", "'$'", "'@'", + "'('", "'['", "'\\n'", "';'", "'{'", "'}'", "')'", "'!'", "'\\\\'", + "']'", "','", "$accept", "prog", "expr_or_assign_or_help", + "expr_or_help", "expr", "cond", "ifcond", "forcond", "exprlist", + "sublist", "sub", "formlist", "cr", YY_NULLPTR }; static const char * @@ -1176,7 +1180,7 @@ yysymbol_name (yysymbol_kind_t yysymbol) } #endif -#define YYPACT_NINF (-130) +#define YYPACT_NINF (-132) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) @@ -1190,24 +1194,24 @@ yysymbol_name (yysymbol_kind_t yysymbol) STATE-NUM. */ static const yytype_int16 yypact[] = { - 139, -130, -130, -11, -130, -130, 2, -49, 10, 27, - 29, -130, -130, 209, -130, 209, 209, 209, 209, 209, - -130, 209, 209, 30, 95, 14, 281, 16, 70, 71, - 77, 88, 89, 209, 209, 209, 209, 209, 86, 86, - 371, 225, 225, 13, 18, -53, 440, 88, -130, 209, - 209, -130, -130, 209, 209, 229, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 209, 82, 84, 229, 229, - -130, -130, -130, -130, -130, -130, -130, -130, 87, -3, - 90, 86, -43, 281, -1, -39, 86, -130, 209, 209, - -130, 3, 86, 86, 281, 326, -5, 91, 0, 55, - 31, -130, 485, 485, 485, 485, 485, 485, 440, 416, - 440, 416, 206, 107, 371, 118, 118, 507, 507, 206, - 225, 225, -130, -130, -130, -130, 35, 36, 209, -130, - 100, 209, 209, -130, 209, -130, 18, 18, -130, 209, - 209, 209, 39, 40, -130, -130, 55, 209, 101, -38, - -130, 86, 209, 55, 55, 55, -130, 229, 86, 209, - -130, 86, -130, 55 + 141, -132, -132, -11, -132, -132, 2, -50, 10, 27, + 29, -132, -132, 212, -132, 212, 212, 212, 212, 212, + -132, 212, 212, 30, 96, 14, 334, 16, 71, 72, + 78, 89, 90, 212, 212, 212, 212, 212, 87, 87, + 473, 102, 102, 13, 18, -54, 543, 89, -132, 212, + 212, -132, -132, 212, 212, 281, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 83, 85, 281, + 281, -132, -132, -132, -132, -132, -132, -132, -132, 88, + -3, 91, 87, -44, 334, -1, -40, 87, -132, 212, + 212, -132, 3, 87, 87, 334, 427, -5, 92, 0, + 55, 31, -132, 589, 589, 589, 589, 589, 589, 543, + 519, 543, 519, 111, 119, 381, 473, 179, 179, 210, + 210, 111, 102, 102, -132, -132, -132, -132, 35, 34, + 212, -132, 103, 212, 212, -132, 212, -132, 18, 18, + -132, 212, 212, 212, 36, 39, -132, -132, 55, 212, + 105, -39, -132, 87, 212, 55, 55, 55, -132, 281, + 87, 212, -132, 87, -132, 55 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -1216,37 +1220,37 @@ static const yytype_int16 yypact[] = static const yytype_int8 yydefact[] = { 0, 6, 2, 13, 12, 14, 16, 0, 0, 0, - 0, 68, 69, 0, 15, 0, 0, 0, 0, 0, - 3, 73, 0, 0, 0, 0, 7, 0, 0, 0, - 0, 89, 0, 0, 0, 0, 0, 0, 53, 23, - 22, 20, 19, 0, 74, 0, 21, 89, 1, 0, - 0, 4, 5, 0, 0, 81, 0, 0, 0, 0, + 0, 69, 70, 0, 15, 0, 0, 0, 0, 0, + 3, 74, 0, 0, 0, 0, 7, 0, 0, 0, + 0, 90, 0, 0, 0, 0, 0, 0, 54, 23, + 22, 20, 19, 0, 75, 0, 21, 90, 1, 0, + 0, 4, 5, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 81, 81, - 59, 58, 63, 62, 57, 56, 61, 60, 90, 0, - 0, 51, 0, 10, 49, 0, 52, 18, 78, 76, - 17, 0, 8, 9, 44, 45, 13, 14, 16, 82, - 94, 79, 37, 36, 32, 33, 34, 35, 38, 39, - 40, 41, 42, 43, 31, 25, 26, 27, 28, 30, - 24, 29, 65, 64, 67, 66, 94, 94, 0, 94, - 0, 0, 0, 71, 0, 70, 77, 75, 94, 85, - 87, 83, 0, 0, 48, 55, 91, 0, 92, 0, - 11, 50, 0, 86, 88, 84, 54, 81, 46, 0, - 72, 47, 80, 93 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 82, 60, 59, 64, 63, 58, 57, 62, 61, 91, + 0, 0, 52, 0, 10, 50, 0, 53, 18, 79, + 77, 17, 0, 8, 9, 45, 46, 13, 14, 16, + 83, 95, 80, 37, 36, 32, 33, 34, 35, 38, + 39, 40, 41, 42, 43, 44, 31, 25, 26, 27, + 28, 30, 24, 29, 66, 65, 68, 67, 95, 95, + 0, 95, 0, 0, 0, 72, 0, 71, 78, 76, + 95, 86, 88, 84, 0, 0, 49, 56, 92, 0, + 93, 0, 11, 51, 0, 87, 89, 85, 55, 82, + 47, 0, 73, 48, 81, 94 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -130, -130, 51, -31, -16, -130, -130, -130, -130, -10, - -52, 69, -129 + -132, -132, 52, -31, -16, -132, -132, -132, -132, -10, + -51, 68, -131 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_uint8 yydefgoto[] = { - 0, 24, 25, 109, 26, 37, 35, 33, 45, 110, - 111, 89, 153 + 0, 24, 25, 110, 26, 37, 35, 33, 45, 111, + 112, 90, 155 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -1254,126 +1258,142 @@ static const yytype_uint8 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 40, 41, 42, 92, 142, 95, 46, 149, 142, 142, - 157, 49, 151, 98, 99, 31, 100, 144, 93, 162, - 93, 80, 27, 28, 81, 49, 49, 143, 27, 28, - 49, 145, 170, 29, 30, 29, 30, 104, 105, 93, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 50, 50, 93, 93, 38, 50, 39, 139, 136, 137, - 43, 140, 44, 148, 32, 82, 84, 140, 83, 85, - 51, 52, 86, 97, 91, 87, 94, 132, 96, 134, - 133, 34, 135, 36, 47, 48, 88, 90, 49, 138, - 102, 103, 142, 150, 152, 154, 141, 156, 158, 155, - 159, 160, 166, 169, 167, 172, 101, 0, 163, 164, - 165, 55, 93, 0, 0, 93, 93, 0, 0, 0, - 0, 0, 55, 93, 93, 93, 0, 0, 173, 0, - 1, 0, 2, 0, 3, 4, 5, 6, 7, 146, - 147, 93, 0, 93, 8, 0, 9, 0, 10, 11, - 12, 13, 66, 0, 67, 74, 0, 0, 75, 76, - 77, 78, 79, 71, 72, 73, 74, 0, 0, 75, - 76, 77, 78, 79, 14, 0, 15, 0, 16, 0, - 0, 0, 17, 18, 0, 161, 0, 0, 0, 0, - 0, 0, 0, 19, 0, 20, 0, 21, 168, 0, - 22, 23, 0, 171, 3, 4, 5, 6, 7, 0, - 55, 0, 0, 0, 8, 0, 9, 0, 10, 11, - 12, 13, 0, 0, 106, 4, 107, 108, 7, 55, - 0, 0, 0, 0, 8, 0, 9, 0, 10, 11, - 12, 13, 67, 0, 14, 0, 15, 0, 16, 0, - 0, 0, 17, 18, 74, 0, 0, 75, 76, 77, - 78, 79, 0, 19, 14, 0, 15, 21, 16, 0, - 22, 23, 17, 18, 0, 0, 75, 76, 77, 78, - 79, 0, 53, 19, 54, 55, 0, 21, 0, 0, - 22, 23, 0, 0, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 66, 0, 67, 0, 0, - 68, 0, 0, 0, 69, 70, 71, 72, 73, 74, - 55, 0, 75, 76, 77, 78, 79, 0, 0, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 0, + 40, 41, 42, 93, 144, 96, 46, 151, 144, 144, + 159, 49, 153, 99, 100, 31, 101, 146, 94, 164, + 94, 81, 27, 28, 82, 49, 49, 145, 27, 28, + 49, 147, 172, 29, 30, 29, 30, 105, 106, 94, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 50, 50, 94, 94, 38, 50, 39, 141, 138, + 139, 43, 142, 44, 150, 32, 83, 85, 142, 84, + 86, 51, 52, 87, 98, 92, 88, 95, 134, 97, + 136, 135, 34, 137, 36, 47, 48, 89, 91, 49, + 140, 103, 104, 144, 152, 154, 156, 143, 157, 158, + 168, 160, 161, 162, 169, 102, 55, 171, 174, 0, + 165, 166, 167, 0, 94, 55, 0, 94, 94, 0, + 0, 0, 0, 55, 0, 94, 94, 94, 0, 0, + 175, 0, 1, 0, 2, 0, 3, 4, 5, 6, + 7, 148, 149, 94, 0, 94, 8, 67, 9, 0, + 10, 11, 12, 13, 76, 77, 78, 79, 80, 0, + 75, 0, 0, 76, 77, 78, 79, 80, 75, 0, + 0, 76, 77, 78, 79, 80, 14, 0, 0, 15, + 0, 16, 0, 55, 0, 17, 18, 0, 163, 0, + 0, 0, 0, 0, 0, 0, 19, 0, 20, 0, + 21, 170, 0, 22, 23, 0, 173, 3, 4, 5, + 6, 7, 0, 66, 55, 67, 0, 8, 0, 9, + 0, 10, 11, 12, 13, 72, 73, 74, 75, 0, + 0, 76, 77, 78, 79, 80, 0, 0, 0, 0, + 0, 0, 0, 0, 66, 0, 67, 14, 0, 0, + 15, 0, 16, 0, 0, 0, 17, 18, 74, 75, + 0, 0, 76, 77, 78, 79, 80, 19, 0, 0, + 0, 21, 0, 0, 22, 23, 107, 4, 108, 109, + 7, 0, 0, 0, 0, 0, 8, 0, 9, 0, + 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 66, 0, 67, 0, 0, 68, 0, 0, 0, 69, - 70, 71, 72, 73, 74, 55, 0, 75, 76, 77, - 78, 79, 0, 0, 56, 57, 58, 59, 60, 61, + 0, 0, 0, 0, 0, 0, 14, 0, 0, 15, + 0, 16, 0, 0, 0, 17, 18, 0, 0, 0, + 0, 0, 0, 0, 0, 53, 19, 54, 55, 0, + 21, 0, 0, 22, 23, 0, 0, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, + 67, 68, 0, 0, 69, 0, 0, 0, 70, 71, + 72, 73, 74, 75, 54, 55, 76, 77, 78, 79, + 80, 0, 0, 0, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 66, 0, 67, 0, 0, - 0, 0, 0, 0, 69, 70, 71, 72, 73, 74, - 55, 0, 75, 76, 77, 78, 79, 0, 0, 56, - 57, 58, 59, 60, 61, 62, 0, 64, 0, 0, - 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, - 66, 0, 67, 56, 57, 58, 59, 60, 61, 69, - 70, 71, 72, 73, 74, 0, 0, 75, 76, 77, - 78, 79, 0, 0, 66, 0, 67, 0, 0, 0, - 0, 0, 0, 69, 70, 71, 72, 73, 74, 55, - 0, 75, 76, 77, 78, 79, 0, 0, -1, -1, - -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, - 0, 55, 0, 0, 0, 0, 0, 0, 0, 66, - 0, 67, 0, 0, 0, 0, 0, 0, 69, 70, - 71, 72, 73, 74, 0, 0, 75, 76, 77, 78, - 79, 66, 0, 67, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 73, 74, 0, 0, 75, 76, - 77, 78, 79 + 0, 0, 0, 0, 0, 66, 0, 67, -1, 0, + 0, 69, 0, 0, 0, 70, 71, 72, 73, 74, + 75, 55, 0, 76, 77, 78, 79, 80, 0, 0, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 66, 0, 67, 0, 0, 0, 69, 0, 0, + 0, 70, 71, 72, 73, 74, 75, 55, 0, 76, + 77, 78, 79, 80, 0, 0, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 66, 0, 67, + 0, 0, 0, 0, 0, 0, 0, 70, 71, 72, + 73, 74, 75, 55, 0, 76, 77, 78, 79, 80, + 0, 0, 56, 57, 58, 59, 60, 61, 62, 0, + 64, 0, 0, 0, 0, 0, 0, 55, 0, 0, + 0, 0, 0, 66, 0, 67, 56, 57, 58, 59, + 60, 61, 0, 70, 71, 72, 73, 74, 75, 0, + 0, 76, 77, 78, 79, 80, 0, 66, 0, 67, + 0, 0, 0, 0, 0, 0, 0, 70, 71, 72, + 73, 74, 75, 55, 0, 76, 77, 78, 79, 80, + 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 66, 0, 67, 0, 0, 0, 0, + 0, 0, 0, 70, 71, 72, 73, 74, 75, 0, + 0, 76, 77, 78, 79, 80 }; static const yytype_int16 yycheck[] = { - 16, 17, 18, 34, 47, 36, 22, 12, 47, 47, - 139, 12, 12, 66, 67, 64, 69, 18, 34, 148, - 36, 5, 33, 34, 8, 12, 12, 70, 33, 34, - 12, 70, 70, 33, 34, 33, 34, 53, 54, 55, + 16, 17, 18, 34, 48, 36, 22, 12, 48, 48, + 141, 12, 12, 67, 68, 65, 70, 18, 34, 150, + 36, 5, 33, 34, 8, 12, 12, 71, 33, 34, + 12, 71, 71, 33, 34, 33, 34, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 47, 47, 78, 79, 13, 47, 15, 70, 78, 79, - 19, 74, 21, 70, 64, 5, 5, 74, 8, 8, - 66, 67, 5, 70, 33, 8, 35, 5, 37, 5, - 8, 64, 8, 64, 64, 0, 8, 8, 12, 12, - 49, 50, 47, 12, 73, 70, 16, 138, 8, 73, - 141, 142, 73, 12, 74, 167, 47, -1, 149, 150, - 151, 14, 138, -1, -1, 141, 142, -1, -1, -1, - -1, -1, 14, 149, 150, 151, -1, -1, 169, -1, - 1, -1, 3, -1, 5, 6, 7, 8, 9, 98, - 99, 167, -1, 169, 15, -1, 17, -1, 19, 20, - 21, 22, 44, -1, 46, 58, -1, -1, 61, 62, - 63, 64, 65, 55, 56, 57, 58, -1, -1, 61, - 62, 63, 64, 65, 45, -1, 47, -1, 49, -1, - -1, -1, 53, 54, -1, 144, -1, -1, -1, -1, - -1, -1, -1, 64, -1, 66, -1, 68, 157, -1, - 71, 72, -1, 162, 5, 6, 7, 8, 9, -1, - 14, -1, -1, -1, 15, -1, 17, -1, 19, 20, - 21, 22, -1, -1, 5, 6, 7, 8, 9, 14, - -1, -1, -1, -1, 15, -1, 17, -1, 19, 20, - 21, 22, 46, -1, 45, -1, 47, -1, 49, -1, - -1, -1, 53, 54, 58, -1, -1, 61, 62, 63, - 64, 65, -1, 64, 45, -1, 47, 68, 49, -1, - 71, 72, 53, 54, -1, -1, 61, 62, 63, 64, - 65, -1, 11, 64, 13, 14, -1, 68, -1, -1, - 71, 72, -1, -1, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 44, -1, 46, -1, -1, - 49, -1, -1, -1, 53, 54, 55, 56, 57, 58, - 14, -1, 61, 62, 63, 64, 65, -1, -1, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, + 76, 48, 48, 79, 80, 13, 48, 15, 71, 79, + 80, 19, 75, 21, 71, 65, 5, 5, 75, 8, + 8, 67, 68, 5, 71, 33, 8, 35, 5, 37, + 5, 8, 65, 8, 65, 65, 0, 8, 8, 12, + 12, 49, 50, 48, 12, 74, 71, 16, 74, 140, + 74, 8, 143, 144, 75, 47, 14, 12, 169, -1, + 151, 152, 153, -1, 140, 14, -1, 143, 144, -1, + -1, -1, -1, 14, -1, 151, 152, 153, -1, -1, + 171, -1, 1, -1, 3, -1, 5, 6, 7, 8, + 9, 99, 100, 169, -1, 171, 15, 46, 17, -1, + 19, 20, 21, 22, 62, 63, 64, 65, 66, -1, + 59, -1, -1, 62, 63, 64, 65, 66, 59, -1, + -1, 62, 63, 64, 65, 66, 45, -1, -1, 48, + -1, 50, -1, 14, -1, 54, 55, -1, 146, -1, + -1, -1, -1, -1, -1, -1, 65, -1, 67, -1, + 69, 159, -1, 72, 73, -1, 164, 5, 6, 7, + 8, 9, -1, 44, 14, 46, -1, 15, -1, 17, + -1, 19, 20, 21, 22, 56, 57, 58, 59, -1, + -1, 62, 63, 64, 65, 66, -1, -1, -1, -1, + -1, -1, -1, -1, 44, -1, 46, 45, -1, -1, + 48, -1, 50, -1, -1, -1, 54, 55, 58, 59, + -1, -1, 62, 63, 64, 65, 66, 65, -1, -1, + -1, 69, -1, -1, 72, 73, 5, 6, 7, 8, + 9, -1, -1, -1, -1, -1, 15, -1, 17, -1, + 19, 20, 21, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 44, -1, 46, -1, -1, 49, -1, -1, -1, 53, - 54, 55, 56, 57, 58, 14, -1, 61, 62, 63, - 64, 65, -1, -1, 23, 24, 25, 26, 27, 28, + -1, -1, -1, -1, -1, -1, 45, -1, -1, 48, + -1, 50, -1, -1, -1, 54, 55, -1, -1, -1, + -1, -1, -1, -1, -1, 11, 65, 13, 14, -1, + 69, -1, -1, 72, 73, -1, -1, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 44, -1, + 46, 47, -1, -1, 50, -1, -1, -1, 54, 55, + 56, 57, 58, 59, 13, 14, 62, 63, 64, 65, + 66, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 44, -1, 46, -1, -1, - -1, -1, -1, -1, 53, 54, 55, 56, 57, 58, - 14, -1, 61, 62, 63, 64, 65, -1, -1, 23, - 24, 25, 26, 27, 28, 29, -1, 31, -1, -1, - -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, - 44, -1, 46, 23, 24, 25, 26, 27, 28, 53, - 54, 55, 56, 57, 58, -1, -1, 61, 62, 63, - 64, 65, -1, -1, 44, -1, 46, -1, -1, -1, - -1, -1, -1, 53, 54, 55, 56, 57, 58, 14, - -1, 61, 62, 63, 64, 65, -1, -1, 23, 24, - 25, 26, 27, 28, -1, -1, -1, -1, -1, -1, - -1, 14, -1, -1, -1, -1, -1, -1, -1, 44, - -1, 46, -1, -1, -1, -1, -1, -1, 53, 54, - 55, 56, 57, 58, -1, -1, 61, 62, 63, 64, - 65, 44, -1, 46, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 57, 58, -1, -1, 61, 62, - 63, 64, 65 + -1, -1, -1, -1, -1, 44, -1, 46, 47, -1, + -1, 50, -1, -1, -1, 54, 55, 56, 57, 58, + 59, 14, -1, 62, 63, 64, 65, 66, -1, -1, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, + -1, 54, 55, 56, 57, 58, 59, 14, -1, 62, + 63, 64, 65, 66, -1, -1, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 44, -1, 46, + -1, -1, -1, -1, -1, -1, -1, 54, 55, 56, + 57, 58, 59, 14, -1, 62, 63, 64, 65, 66, + -1, -1, 23, 24, 25, 26, 27, 28, 29, -1, + 31, -1, -1, -1, -1, -1, -1, 14, -1, -1, + -1, -1, -1, 44, -1, 46, 23, 24, 25, 26, + 27, 28, -1, 54, 55, 56, 57, 58, 59, -1, + -1, 62, 63, 64, 65, 66, -1, 44, -1, 46, + -1, -1, -1, -1, -1, -1, -1, 54, 55, 56, + 57, 58, 59, 14, -1, 62, 63, 64, 65, 66, + -1, -1, 23, 24, 25, 26, 27, 28, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 44, -1, 46, -1, -1, -1, -1, + -1, -1, -1, 54, 55, 56, 57, 58, 59, -1, + -1, 62, 63, 64, 65, 66 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of @@ -1381,38 +1401,38 @@ static const yytype_int16 yycheck[] = static const yytype_int8 yystos[] = { 0, 1, 3, 5, 6, 7, 8, 9, 15, 17, - 19, 20, 21, 22, 45, 47, 49, 53, 54, 64, - 66, 68, 71, 72, 76, 77, 79, 33, 34, 33, - 34, 64, 64, 82, 64, 81, 64, 80, 77, 77, - 79, 79, 79, 77, 77, 83, 79, 64, 0, 12, - 47, 66, 67, 11, 13, 14, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 44, 46, 49, 53, - 54, 55, 56, 57, 58, 61, 62, 63, 64, 65, - 5, 8, 5, 8, 5, 8, 5, 8, 8, 86, - 8, 77, 78, 79, 77, 78, 77, 70, 66, 67, - 69, 86, 77, 77, 79, 79, 5, 7, 8, 78, - 84, 85, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 5, 8, 5, 8, 84, 84, 12, 70, - 74, 16, 47, 70, 18, 70, 77, 77, 70, 12, - 12, 12, 73, 87, 70, 73, 78, 87, 8, 78, - 78, 77, 87, 78, 78, 78, 73, 74, 77, 12, - 70, 77, 85, 78 + 19, 20, 21, 22, 45, 48, 50, 54, 55, 65, + 67, 69, 72, 73, 77, 78, 80, 33, 34, 33, + 34, 65, 65, 83, 65, 82, 65, 81, 78, 78, + 80, 80, 80, 78, 78, 84, 80, 65, 0, 12, + 48, 67, 68, 11, 13, 14, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 44, 46, 47, 50, + 54, 55, 56, 57, 58, 59, 62, 63, 64, 65, + 66, 5, 8, 5, 8, 5, 8, 5, 8, 8, + 87, 8, 78, 79, 80, 78, 79, 78, 71, 67, + 68, 70, 87, 78, 78, 80, 80, 5, 7, 8, + 79, 85, 86, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 5, 8, 5, 8, 85, 85, + 12, 71, 75, 16, 48, 71, 18, 71, 78, 78, + 71, 12, 12, 12, 74, 88, 71, 74, 79, 88, + 8, 79, 79, 78, 88, 79, 79, 79, 74, 75, + 78, 12, 71, 78, 86, 79 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { - 0, 75, 76, 76, 76, 76, 76, 77, 77, 77, - 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 80, 81, 82, 83, 83, 83, 83, 83, 83, 84, - 84, 85, 85, 85, 85, 85, 85, 85, 85, 86, - 86, 86, 86, 86, 87 + 0, 76, 77, 77, 77, 77, 77, 78, 78, 78, + 79, 79, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 81, 82, 83, 84, 84, 84, 84, 84, 84, + 85, 85, 86, 86, 86, 86, 86, 86, 86, 86, + 87, 87, 87, 87, 87, 88 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ @@ -1422,12 +1442,12 @@ static const yytype_int8 yyr2[] = 1, 3, 1, 1, 1, 1, 1, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 6, 6, 4, 3, - 5, 3, 3, 2, 5, 4, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, - 3, 3, 5, 0, 1, 3, 2, 3, 2, 1, - 4, 0, 1, 2, 3, 2, 3, 2, 3, 0, - 1, 3, 3, 5, 0 + 3, 3, 3, 3, 3, 3, 3, 6, 6, 4, + 3, 5, 3, 3, 2, 5, 4, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, + 1, 3, 3, 5, 0, 1, 3, 2, 3, 2, + 1, 4, 0, 1, 2, 3, 2, 3, 2, 3, + 0, 1, 3, 3, 5, 0 }; @@ -2442,207 +2462,211 @@ yyparse (void) { yyval = xxpipebind(yyvsp[-1],yyvsp[-2],yyvsp[0],&(yylsp[-1])); setId((yyloc)); } break; - case 44: /* expr: expr LEFT_ASSIGN expr */ + case 44: /* expr: expr PIPE_ASSIGN expr */ + { yyval = xxpipeassign(yyvsp[-2],yyvsp[0],&(yylsp[-2]),&(yylsp[0])); setId((yyloc)); } + break; + + case 45: /* expr: expr LEFT_ASSIGN expr */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); } break; - case 45: /* expr: expr RIGHT_ASSIGN expr */ + case 46: /* expr: expr RIGHT_ASSIGN expr */ { yyval = xxbinary(yyvsp[-1],yyvsp[0],yyvsp[-2]); setId((yyloc)); } break; - case 46: /* expr: FUNCTION '(' formlist ')' cr expr_or_assign_or_help */ + case 47: /* expr: FUNCTION '(' formlist ')' cr expr_or_assign_or_help */ { yyval = xxdefun(yyvsp[-5],yyvsp[-3],yyvsp[0],&(yyloc)); setId((yyloc)); } break; - case 47: /* expr: '\\' '(' formlist ')' cr expr_or_assign_or_help */ + case 48: /* expr: '\\' '(' formlist ')' cr expr_or_assign_or_help */ { yyval = xxdefun(R_FunctionSymbol,yyvsp[-3],yyvsp[0],&(yyloc)); setId((yyloc)); } break; - case 48: /* expr: expr '(' sublist ')' */ + case 49: /* expr: expr '(' sublist ')' */ { yyval = xxfuncall(yyvsp[-3],yyvsp[-1]); setId((yyloc)); modif_token( &(yylsp[-3]), SYMBOL_FUNCTION_CALL ) ; } break; - case 49: /* expr: IF ifcond expr_or_assign_or_help */ + case 50: /* expr: IF ifcond expr_or_assign_or_help */ { yyval = xxif(yyvsp[-2],yyvsp[-1],yyvsp[0]); setId((yyloc)); } break; - case 50: /* expr: IF ifcond expr_or_assign_or_help ELSE expr_or_assign_or_help */ + case 51: /* expr: IF ifcond expr_or_assign_or_help ELSE expr_or_assign_or_help */ { yyval = xxifelse(yyvsp[-4],yyvsp[-3],yyvsp[-2],yyvsp[0]); setId((yyloc)); } break; - case 51: /* expr: FOR forcond expr_or_assign_or_help */ + case 52: /* expr: FOR forcond expr_or_assign_or_help */ { yyval = xxfor(yyvsp[-2],yyvsp[-1],yyvsp[0]); setId((yyloc)); } break; - case 52: /* expr: WHILE cond expr_or_assign_or_help */ + case 53: /* expr: WHILE cond expr_or_assign_or_help */ { yyval = xxwhile(yyvsp[-2],yyvsp[-1],yyvsp[0]); setId((yyloc)); } break; - case 53: /* expr: REPEAT expr_or_assign_or_help */ + case 54: /* expr: REPEAT expr_or_assign_or_help */ { yyval = xxrepeat(yyvsp[-1],yyvsp[0]); setId((yyloc)); } break; - case 54: /* expr: expr LBB sublist ']' ']' */ + case 55: /* expr: expr LBB sublist ']' ']' */ { yyval = xxsubscript(yyvsp[-4],yyvsp[-3],yyvsp[-2]); setId((yyloc)); } break; - case 55: /* expr: expr '[' sublist ']' */ + case 56: /* expr: expr '[' sublist ']' */ { yyval = xxsubscript(yyvsp[-3],yyvsp[-2],yyvsp[-1]); setId((yyloc)); } break; - case 56: /* expr: SYMBOL NS_GET SYMBOL */ + case 57: /* expr: SYMBOL NS_GET SYMBOL */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); modif_token( &(yylsp[-2]), SYMBOL_PACKAGE ) ; } break; - case 57: /* expr: SYMBOL NS_GET STR_CONST */ + case 58: /* expr: SYMBOL NS_GET STR_CONST */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); modif_token( &(yylsp[-2]), SYMBOL_PACKAGE ) ; } break; - case 58: /* expr: STR_CONST NS_GET SYMBOL */ + case 59: /* expr: STR_CONST NS_GET SYMBOL */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); } break; - case 59: /* expr: STR_CONST NS_GET STR_CONST */ + case 60: /* expr: STR_CONST NS_GET STR_CONST */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); } break; - case 60: /* expr: SYMBOL NS_GET_INT SYMBOL */ + case 61: /* expr: SYMBOL NS_GET_INT SYMBOL */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); modif_token( &(yylsp[-2]), SYMBOL_PACKAGE ) ;} break; - case 61: /* expr: SYMBOL NS_GET_INT STR_CONST */ + case 62: /* expr: SYMBOL NS_GET_INT STR_CONST */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); modif_token( &(yylsp[-2]), SYMBOL_PACKAGE ) ;} break; - case 62: /* expr: STR_CONST NS_GET_INT SYMBOL */ + case 63: /* expr: STR_CONST NS_GET_INT SYMBOL */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); } break; - case 63: /* expr: STR_CONST NS_GET_INT STR_CONST */ + case 64: /* expr: STR_CONST NS_GET_INT STR_CONST */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); } break; - case 64: /* expr: expr '$' SYMBOL */ + case 65: /* expr: expr '$' SYMBOL */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); } break; - case 65: /* expr: expr '$' STR_CONST */ + case 66: /* expr: expr '$' STR_CONST */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); } break; - case 66: /* expr: expr '@' SYMBOL */ + case 67: /* expr: expr '@' SYMBOL */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); modif_token( &(yylsp[0]), SLOT ) ; } break; - case 67: /* expr: expr '@' STR_CONST */ + case 68: /* expr: expr '@' STR_CONST */ { yyval = xxbinary(yyvsp[-1],yyvsp[-2],yyvsp[0]); setId((yyloc)); } break; - case 68: /* expr: NEXT */ + case 69: /* expr: NEXT */ { yyval = xxnxtbrk(yyvsp[0]); setId((yyloc)); } break; - case 69: /* expr: BREAK */ + case 70: /* expr: BREAK */ { yyval = xxnxtbrk(yyvsp[0]); setId((yyloc)); } break; - case 70: /* cond: '(' expr_or_help ')' */ + case 71: /* cond: '(' expr_or_help ')' */ { yyval = xxcond(yyvsp[-1]); } break; - case 71: /* ifcond: '(' expr_or_help ')' */ + case 72: /* ifcond: '(' expr_or_help ')' */ { yyval = xxifcond(yyvsp[-1]); } break; - case 72: /* forcond: '(' SYMBOL IN expr_or_help ')' */ + case 73: /* forcond: '(' SYMBOL IN expr_or_help ')' */ { yyval = xxforcond(yyvsp[-3],yyvsp[-1]); setId((yyloc)); } break; - case 73: /* exprlist: %empty */ + case 74: /* exprlist: %empty */ { yyval = xxexprlist0(); setId((yyloc)); } break; - case 74: /* exprlist: expr_or_assign_or_help */ + case 75: /* exprlist: expr_or_assign_or_help */ { yyval = xxexprlist1(yyvsp[0], &(yylsp[0])); } break; - case 75: /* exprlist: exprlist ';' expr_or_assign_or_help */ + case 76: /* exprlist: exprlist ';' expr_or_assign_or_help */ { yyval = xxexprlist2(yyvsp[-2], yyvsp[0], &(yylsp[0])); } break; - case 76: /* exprlist: exprlist ';' */ + case 77: /* exprlist: exprlist ';' */ { yyval = yyvsp[-1]; setId((yyloc)); } break; - case 77: /* exprlist: exprlist '\n' expr_or_assign_or_help */ + case 78: /* exprlist: exprlist '\n' expr_or_assign_or_help */ { yyval = xxexprlist2(yyvsp[-2], yyvsp[0], &(yylsp[0])); } break; - case 78: /* exprlist: exprlist '\n' */ + case 79: /* exprlist: exprlist '\n' */ { yyval = yyvsp[-1];} break; - case 79: /* sublist: sub */ + case 80: /* sublist: sub */ { yyval = xxsublist1(yyvsp[0]); } break; - case 80: /* sublist: sublist cr ',' sub */ + case 81: /* sublist: sublist cr ',' sub */ { yyval = xxsublist2(yyvsp[-3],yyvsp[0]); } break; - case 81: /* sub: %empty */ + case 82: /* sub: %empty */ { yyval = xxsub0(); } break; - case 82: /* sub: expr_or_help */ + case 83: /* sub: expr_or_help */ { yyval = xxsub1(yyvsp[0], &(yylsp[0])); } break; - case 83: /* sub: SYMBOL EQ_ASSIGN */ + case 84: /* sub: SYMBOL EQ_ASSIGN */ { yyval = xxsymsub0(yyvsp[-1], &(yylsp[-1])); modif_token( &(yylsp[0]), EQ_SUB ) ; modif_token( &(yylsp[-1]), SYMBOL_SUB ) ; } break; - case 84: /* sub: SYMBOL EQ_ASSIGN expr_or_help */ + case 85: /* sub: SYMBOL EQ_ASSIGN expr_or_help */ { yyval = xxsymsub1(yyvsp[-2],yyvsp[0], &(yylsp[-2])); modif_token( &(yylsp[-1]), EQ_SUB ) ; modif_token( &(yylsp[-2]), SYMBOL_SUB ) ; } break; - case 85: /* sub: STR_CONST EQ_ASSIGN */ + case 86: /* sub: STR_CONST EQ_ASSIGN */ { yyval = xxsymsub0(yyvsp[-1], &(yylsp[-1])); modif_token( &(yylsp[0]), EQ_SUB ) ; } break; - case 86: /* sub: STR_CONST EQ_ASSIGN expr_or_help */ + case 87: /* sub: STR_CONST EQ_ASSIGN expr_or_help */ { yyval = xxsymsub1(yyvsp[-2],yyvsp[0], &(yylsp[-2])); modif_token( &(yylsp[-1]), EQ_SUB ) ; } break; - case 87: /* sub: NULL_CONST EQ_ASSIGN */ + case 88: /* sub: NULL_CONST EQ_ASSIGN */ { yyval = xxnullsub0(&(yylsp[-1])); modif_token( &(yylsp[0]), EQ_SUB ) ; } break; - case 88: /* sub: NULL_CONST EQ_ASSIGN expr_or_help */ + case 89: /* sub: NULL_CONST EQ_ASSIGN expr_or_help */ { yyval = xxnullsub1(yyvsp[0], &(yylsp[-2])); modif_token( &(yylsp[-1]), EQ_SUB ) ; } break; - case 89: /* formlist: %empty */ + case 90: /* formlist: %empty */ { yyval = xxnullformal(); } break; - case 90: /* formlist: SYMBOL */ + case 91: /* formlist: SYMBOL */ { yyval = xxfirstformal0(yyvsp[0]); modif_token( &(yylsp[0]), SYMBOL_FORMALS ) ; } break; - case 91: /* formlist: SYMBOL EQ_ASSIGN expr_or_help */ + case 92: /* formlist: SYMBOL EQ_ASSIGN expr_or_help */ { yyval = xxfirstformal1(yyvsp[-2],yyvsp[0]); modif_token( &(yylsp[-2]), SYMBOL_FORMALS ) ; modif_token( &(yylsp[-1]), EQ_FORMALS ) ; } break; - case 92: /* formlist: formlist ',' SYMBOL */ + case 93: /* formlist: formlist ',' SYMBOL */ { yyval = xxaddformal0(yyvsp[-2],yyvsp[0], &(yylsp[0])); modif_token( &(yylsp[0]), SYMBOL_FORMALS ) ; } break; - case 93: /* formlist: formlist ',' SYMBOL EQ_ASSIGN expr_or_help */ + case 94: /* formlist: formlist ',' SYMBOL EQ_ASSIGN expr_or_help */ { yyval = xxaddformal1(yyvsp[-4],yyvsp[-2],yyvsp[0],&(yylsp[-2])); modif_token( &(yylsp[-2]), SYMBOL_FORMALS ) ; modif_token( &(yylsp[-1]), EQ_FORMALS ) ;} break; - case 94: /* cr: %empty */ + case 95: /* cr: %empty */ { EatLines = 1; } break; @@ -3640,11 +3664,69 @@ static SEXP xxpipebind(SEXP fn, SEXP lhs, SEXP rhs, YYLTYPE *lloc_bind) if (use_pipebind) return xxbinary(fn, lhs, rhs); else - raiseParseError("pipebindDisabled", R_NilValue, + raiseParseError("pipebindDisabled", R_NilValue, NO_VALUE, NULL, lloc_bind, _("'=>' is disabled; set '_R_USE_PIPEBIND_' envvar to a true value to enable it (%s:%d:%d)")); } +static SEXP xxpipeassign(SEXP lhs, SEXP rhs, YYLTYPE *lloc_lhs, YYLTYPE *lloc_rhs) +{ + SEXP ans; + + if (GenerateCode) { + /* Validate RHS is a function call */ + if (TYPEOF(rhs) != LANGSXP) + raiseParseError("RHSnotFnCall", rhs, NO_VALUE, NULL, lloc_rhs, + _("The pipe assignment operator requires a function call as RHS (%s:%d:%d)")); + + /* Duplicate the LHS for reading */ + SEXP lhs_read = duplicate(lhs); + PRESERVE_SV(lhs_read); + + /* Check for placeholder in RHS function name */ + if (checkForPlaceholder(R_PlaceholderToken, CAR(rhs))) + raiseParseError("placeholderInRHSFn", R_NilValue, + NO_VALUE, NULL, lloc_rhs, + _("pipe placeholder cannot be used in the RHS function (%s:%d:%d)")); + + /* Handle top-level placeholder in arguments */ + SEXP placeholder_found = NULL; + for (SEXP a = CDR(rhs); a != R_NilValue; a = CDR(a)) { + if (CAR(a) == R_PlaceholderToken) { + if (TAG(a) == R_NilValue) + raiseParseError("placeholderNotNamed", rhs, + NO_VALUE, NULL, lloc_rhs, + _("pipe placeholder can only be used as a named argument (%s:%d:%d)")); + if (placeholder_found != NULL) + raiseParseError("tooManyPlaceholders", rhs, + NO_VALUE, NULL, lloc_rhs, + _("pipe placeholder may only appear once (%s:%d:%d)")); + placeholder_found = a; + } + } + + if (placeholder_found != NULL) { + /* Replace placeholder with LHS */ + SETCAR(placeholder_found, lhs_read); + PRESERVE_SV(ans = xxbinary(install("<-"), lhs, rhs)); + } else { + /* Default: prepend LHS to arguments */ + check_rhs(rhs, lloc_rhs); + SEXP fun = CAR(rhs); + SEXP args = CDR(rhs); + SEXP new_call = lcons(fun, lcons(lhs_read, args)); + PRESERVE_SV(ans = xxbinary(install("<-"), lhs, new_call)); + } + RELEASE_SV(lhs_read); + } + else { + PRESERVE_SV(ans = R_NilValue); + } + RELEASE_SV(lhs); + RELEASE_SV(rhs); + return ans; +} + static SEXP xxparen(SEXP n1, SEXP n2) { SEXP ans; @@ -4660,6 +4742,7 @@ static void yyerror(const char *s) "NS_GET_INT", "':::'", "PIPE", "'|>'", "PIPEBIND", "'=>'", + "PIPE_ASSIGN", "'<|>'", "PLACEHOLDER", "'_'", 0 }; @@ -5908,6 +5991,14 @@ static int token(void) else return ERROR; } + if (nextchar('|')) { + if (nextchar('>')) { + yylval = install_and_save("<|>"); + return PIPE_ASSIGN; + } + else + return ERROR; + } yylval = install_and_save("<"); return LT; case '-': diff --git a/src/main/gram.y b/src/main/gram.y index 2f6b34e6c53..fb86b261445 100644 --- a/src/main/gram.y +++ b/src/main/gram.y @@ -385,6 +385,7 @@ static SEXP xxfuncall(SEXP, SEXP); static SEXP xxdefun(SEXP, SEXP, SEXP, YYLTYPE *); static SEXP xxpipe(SEXP, SEXP, YYLTYPE *); static SEXP xxpipebind(SEXP, SEXP, SEXP, YYLTYPE *); +static SEXP xxpipeassign(SEXP, SEXP, YYLTYPE *, YYLTYPE *); static SEXP xxunary(SEXP, SEXP); static SEXP xxbinary(SEXP, SEXP, SEXP); static SEXP xxparen(SEXP, SEXP); @@ -416,6 +417,7 @@ static int xxvalue(SEXP, int, YYLTYPE *); %token PIPE %token PLACEHOLDER %token PIPEBIND +%token PIPE_ASSIGN /* This is the precedence table, low to high */ %left '?' @@ -424,6 +426,7 @@ static int xxvalue(SEXP, int, YYLTYPE *); %left ELSE %right LEFT_ASSIGN %right EQ_ASSIGN +%nonassoc PIPE_ASSIGN %left RIGHT_ASSIGN %left '~' TILDE %left OR OR2 @@ -494,6 +497,7 @@ expr : NUM_CONST { $$ = $1; setId(@$); } | expr OR2 expr { $$ = xxbinary($2,$1,$3); setId(@$); } | expr PIPE expr { $$ = xxpipe($1,$3,&@3); setId(@$); } | expr PIPEBIND expr { $$ = xxpipebind($2,$1,$3,&@2); setId(@$); } + | expr PIPE_ASSIGN expr { $$ = xxpipeassign($1,$3,&@1,&@3); setId(@$); } | expr LEFT_ASSIGN expr { $$ = xxbinary($2,$1,$3); setId(@$); } | expr RIGHT_ASSIGN expr { $$ = xxbinary($2,$3,$1); setId(@$); } | FUNCTION '(' formlist ')' cr expr_or_assign_or_help %prec LOW @@ -1331,11 +1335,69 @@ static SEXP xxpipebind(SEXP fn, SEXP lhs, SEXP rhs, YYLTYPE *lloc_bind) if (use_pipebind) return xxbinary(fn, lhs, rhs); else - raiseParseError("pipebindDisabled", R_NilValue, + raiseParseError("pipebindDisabled", R_NilValue, NO_VALUE, NULL, lloc_bind, _("'=>' is disabled; set '_R_USE_PIPEBIND_' envvar to a true value to enable it (%s:%d:%d)")); } +static SEXP xxpipeassign(SEXP lhs, SEXP rhs, YYLTYPE *lloc_lhs, YYLTYPE *lloc_rhs) +{ + SEXP ans; + + if (GenerateCode) { + /* Validate RHS is a function call */ + if (TYPEOF(rhs) != LANGSXP) + raiseParseError("RHSnotFnCall", rhs, NO_VALUE, NULL, lloc_rhs, + _("The pipe assignment operator requires a function call as RHS (%s:%d:%d)")); + + /* Duplicate the LHS for reading */ + SEXP lhs_read = duplicate(lhs); + PRESERVE_SV(lhs_read); + + /* Check for placeholder in RHS function name */ + if (checkForPlaceholder(R_PlaceholderToken, CAR(rhs))) + raiseParseError("placeholderInRHSFn", R_NilValue, + NO_VALUE, NULL, lloc_rhs, + _("pipe placeholder cannot be used in the RHS function (%s:%d:%d)")); + + /* Handle top-level placeholder in arguments */ + SEXP placeholder_found = NULL; + for (SEXP a = CDR(rhs); a != R_NilValue; a = CDR(a)) { + if (CAR(a) == R_PlaceholderToken) { + if (TAG(a) == R_NilValue) + raiseParseError("placeholderNotNamed", rhs, + NO_VALUE, NULL, lloc_rhs, + _("pipe placeholder can only be used as a named argument (%s:%d:%d)")); + if (placeholder_found != NULL) + raiseParseError("tooManyPlaceholders", rhs, + NO_VALUE, NULL, lloc_rhs, + _("pipe placeholder may only appear once (%s:%d:%d)")); + placeholder_found = a; + } + } + + if (placeholder_found != NULL) { + /* Replace placeholder with LHS */ + SETCAR(placeholder_found, lhs_read); + PRESERVE_SV(ans = xxbinary(install("<-"), lhs, rhs)); + } else { + /* Default: prepend LHS to arguments */ + check_rhs(rhs, lloc_rhs); + SEXP fun = CAR(rhs); + SEXP args = CDR(rhs); + SEXP new_call = lcons(fun, lcons(lhs_read, args)); + PRESERVE_SV(ans = xxbinary(install("<-"), lhs, new_call)); + } + RELEASE_SV(lhs_read); + } + else { + PRESERVE_SV(ans = R_NilValue); + } + RELEASE_SV(lhs); + RELEASE_SV(rhs); + return ans; +} + static SEXP xxparen(SEXP n1, SEXP n2) { SEXP ans; @@ -2351,6 +2413,7 @@ static void yyerror(const char *s) "NS_GET_INT", "':::'", "PIPE", "'|>'", "PIPEBIND", "'=>'", + "PIPE_ASSIGN", "'<|>'", "PLACEHOLDER", "'_'", 0 }; @@ -3599,6 +3662,14 @@ static int token(void) else return ERROR; } + if (nextchar('|')) { + if (nextchar('>')) { + yylval = install_and_save("<|>"); + return PIPE_ASSIGN; + } + else + return ERROR; + } yylval = install_and_save("<"); return LT; case '-': diff --git a/tests/reg-tests-pipe-assign.R b/tests/reg-tests-pipe-assign.R new file mode 100644 index 00000000000..2a100b04d1e --- /dev/null +++ b/tests/reg-tests-pipe-assign.R @@ -0,0 +1,102 @@ +#### Regression tests for pipe assignment operator <|> + +## Basic usage with simple variables +x <- 5 +x <|> sqrt() +stopifnot(identical(x, sqrt(5))) + +x <- 16 +x <|> sqrt() +stopifnot(identical(x, 4)) + +## Subscripting with [ +x <- c(1, 4, 9, 16) +x[2] <|> sqrt() +stopifnot(identical(x, c(1, 2, 9, 16))) + +x <- c(1, 4, 9) +x[c(1,3)] <|> sqrt() +stopifnot(identical(x, c(1, 4, 3))) + +## Subscripting with [[ +x <- list(1, 4, 9) +x[[2]] <|> sqrt() +stopifnot(identical(x, list(1, 2, 9))) + +## Field extraction with $ +x <- list(a = 4, b = 9) +x$a <|> sqrt() +stopifnot(identical(x$a, 2)) +stopifnot(identical(x$b, 9)) + +## Names replacement function +x <- c(a=1, b=2, c=3) +names(x) <|> toupper() +stopifnot(identical(names(x), c("A", "B", "C"))) + +## Attributes +x <- 1:5 +attr(x, "test") <- "hello" +attr(x, "test") <|> toupper() +stopifnot(identical(attr(x, "test"), "HELLO")) + +## Multiple arguments (data-first function) +x <- c(3, 1, 2) +x <|> sort(decreasing = TRUE) +stopifnot(identical(x, c(3, 2, 1))) + +x <- c(3, 1, 2) +x <|> sort(decreasing = TRUE) +stopifnot(identical(x, c(3, 2, 1))) + +## Placeholder in named argument +x <- "hello" +x <|> sub("h", "H", x = _) +stopifnot(identical(x, "Hello")) + +x <- "hello" +x <|> gsub("l", "L", x = _) +stopifnot(identical(x, "heLLo")) + +## Error cases +## RHS not a function call +tryCatch( + eval(parse(text = "x <|> 5")), + error = function(e) { + msg <- conditionMessage(e) + if (!grepl("requires a function call", msg)) + stop("Expected error about RHS not being function call") + } +) + +## Multiple placeholders (should error) +tryCatch( + eval(parse(text = "x <|> f(a = _, b = _)")), + error = function(e) { + msg <- conditionMessage(e) + if (!grepl("only appear once", msg)) + stop("Expected error about multiple placeholders") + } +) + +## Placeholder not named (should error) +tryCatch( + eval(parse(text = "x <|> f(_)")), + error = function(e) { + msg <- conditionMessage(e) + if (!grepl("named argument", msg)) + stop("Expected error about placeholder not being named") + } +) + +## Chaining should error (non-associative) +tryCatch( + eval(parse(text = "x <|> f() <|> g()")), + error = function(e) { + msg <- conditionMessage(e) + # Parser error expected + TRUE + } +) + +cat("All pipe assignment tests passed!\n") From ed7a20d0ae1bdc78729db666bbf28691587b35d2 Mon Sep 17 00:00:00 2001 From: David Hugh-Jones Date: Sun, 7 Dec 2025 08:08:58 +0000 Subject: [PATCH 2/2] Refactor xxpipeassign to use checkTooManyPlaceholders helper --- src/main/gram.c | 6 ++---- src/main/gram.y | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/gram.c b/src/main/gram.c index 97d5f46182f..5622e7ec52d 100644 --- a/src/main/gram.c +++ b/src/main/gram.c @@ -3697,11 +3697,9 @@ static SEXP xxpipeassign(SEXP lhs, SEXP rhs, YYLTYPE *lloc_lhs, YYLTYPE *lloc_rh raiseParseError("placeholderNotNamed", rhs, NO_VALUE, NULL, lloc_rhs, _("pipe placeholder can only be used as a named argument (%s:%d:%d)")); - if (placeholder_found != NULL) - raiseParseError("tooManyPlaceholders", rhs, - NO_VALUE, NULL, lloc_rhs, - _("pipe placeholder may only appear once (%s:%d:%d)")); + checkTooManyPlaceholders(rhs, CDR(a), lloc_rhs); placeholder_found = a; + break; } } diff --git a/src/main/gram.y b/src/main/gram.y index fb86b261445..0da010a85ab 100644 --- a/src/main/gram.y +++ b/src/main/gram.y @@ -1368,11 +1368,9 @@ static SEXP xxpipeassign(SEXP lhs, SEXP rhs, YYLTYPE *lloc_lhs, YYLTYPE *lloc_rh raiseParseError("placeholderNotNamed", rhs, NO_VALUE, NULL, lloc_rhs, _("pipe placeholder can only be used as a named argument (%s:%d:%d)")); - if (placeholder_found != NULL) - raiseParseError("tooManyPlaceholders", rhs, - NO_VALUE, NULL, lloc_rhs, - _("pipe placeholder may only appear once (%s:%d:%d)")); + checkTooManyPlaceholders(rhs, CDR(a), lloc_rhs); placeholder_found = a; + break; } }