@@ -465,6 +465,16 @@ static const uint8_t *peg_rule(
465
465
return result ;
466
466
}
467
467
468
+ case RULE_ONLY_TAGS : {
469
+ CapState cs = cap_save (s );
470
+ down1 (s );
471
+ const uint8_t * result = peg_rule (s , s -> bytecode + rule [1 ], text );
472
+ up1 (s );
473
+ if (!result ) return NULL ;
474
+ cap_load_keept (s , cs );
475
+ return result ;
476
+ }
477
+
468
478
case RULE_GROUP : {
469
479
uint32_t tag = rule [2 ];
470
480
int oldmode = s -> mode ;
@@ -486,6 +496,29 @@ static const uint8_t *peg_rule(
486
496
return result ;
487
497
}
488
498
499
+ case RULE_NTH : {
500
+ uint32_t nth = rule [1 ];
501
+ uint32_t tag = rule [3 ];
502
+ int oldmode = s -> mode ;
503
+ CapState cs = cap_save (s );
504
+ s -> mode = PEG_MODE_NORMAL ;
505
+ down1 (s );
506
+ const uint8_t * result = peg_rule (s , s -> bytecode + rule [2 ], text );
507
+ up1 (s );
508
+ s -> mode = oldmode ;
509
+ if (!result ) return NULL ;
510
+ int32_t num_sub_captures = s -> captures -> count - cs .cap ;
511
+ Janet cap ;
512
+ if (num_sub_captures > (int32_t ) nth ) {
513
+ cap = s -> captures -> data [cs .cap + nth ];
514
+ } else {
515
+ return NULL ;
516
+ }
517
+ cap_load_keept (s , cs );
518
+ pushcap (s , cap , tag );
519
+ return result ;
520
+ }
521
+
489
522
case RULE_SUB : {
490
523
const uint8_t * text_start = text ;
491
524
const uint32_t * rule_window = s -> bytecode + rule [1 ];
@@ -1061,6 +1094,9 @@ static void spec_thru(Builder *b, int32_t argc, const Janet *argv) {
1061
1094
static void spec_drop (Builder * b , int32_t argc , const Janet * argv ) {
1062
1095
spec_onerule (b , argc , argv , RULE_DROP );
1063
1096
}
1097
+ static void spec_only_tags (Builder * b , int32_t argc , const Janet * argv ) {
1098
+ spec_onerule (b , argc , argv , RULE_ONLY_TAGS );
1099
+ }
1064
1100
1065
1101
/* Rule of the form [rule, tag] */
1066
1102
static void spec_cap1 (Builder * b , int32_t argc , const Janet * argv , uint32_t op ) {
@@ -1084,6 +1120,15 @@ static void spec_unref(Builder *b, int32_t argc, const Janet *argv) {
1084
1120
spec_cap1 (b , argc , argv , RULE_UNREF );
1085
1121
}
1086
1122
1123
+ static void spec_nth (Builder * b , int32_t argc , const Janet * argv ) {
1124
+ peg_arity (b , argc , 2 , 3 );
1125
+ Reserve r = reserve (b , 4 );
1126
+ uint32_t nth = peg_getnat (b , argv [0 ]);
1127
+ uint32_t rule = peg_compile1 (b , argv [1 ]);
1128
+ uint32_t tag = (argc == 3 ) ? emit_tag (b , argv [2 ]) : 0 ;
1129
+ emit_3 (r , RULE_NTH , nth , rule , tag );
1130
+ }
1131
+
1087
1132
static void spec_capture_number (Builder * b , int32_t argc , const Janet * argv ) {
1088
1133
peg_arity (b , argc , 1 , 3 );
1089
1134
Reserve r = reserve (b , 4 );
@@ -1262,7 +1307,9 @@ static const SpecialPair peg_specials[] = {
1262
1307
{"line" , spec_line },
1263
1308
{"look" , spec_look },
1264
1309
{"not" , spec_not },
1310
+ {"nth" , spec_nth },
1265
1311
{"number" , spec_capture_number },
1312
+ {"only-tags" , spec_only_tags },
1266
1313
{"opt" , spec_opt },
1267
1314
{"position" , spec_position },
1268
1315
{"quote" , spec_capture },
@@ -1619,6 +1666,7 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
1619
1666
break ;
1620
1667
case RULE_ERROR :
1621
1668
case RULE_DROP :
1669
+ case RULE_ONLY_TAGS :
1622
1670
case RULE_NOT :
1623
1671
case RULE_TO :
1624
1672
case RULE_THRU :
@@ -1632,6 +1680,12 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
1632
1680
if (rule [1 ] > JANET_MAX_READINT_WIDTH ) goto bad ;
1633
1681
i += 3 ;
1634
1682
break ;
1683
+ case RULE_NTH :
1684
+ /* [nth, rule, tag] */
1685
+ if (rule [2 ] >= blen ) goto bad ;
1686
+ op_flags [rule [2 ]] |= 0x01 ;
1687
+ i += 4 ;
1688
+ break ;
1635
1689
default :
1636
1690
goto bad ;
1637
1691
}
0 commit comments