@@ -37,12 +37,19 @@ enum Parse_Flags {
37
37
PF_CASED = 4 , // was set as initial option
38
38
};
39
39
40
+ typedef struct reb_parse_collect {
41
+ REBVAL * result ;
42
+ REBSER * block ;
43
+ REBINT depth ;
44
+ } REB_PARSE_COLLECT ;
45
+
40
46
typedef struct reb_parse {
41
47
REBSER * series ;
42
48
REBCNT type ;
43
49
REBCNT flags ;
44
50
REBINT result ;
45
- REBVAL retval ;
51
+ REBVAL * retval ;
52
+ REB_PARSE_COLLECT * collect ;
46
53
} REBPARSE ;
47
54
48
55
enum parse_flags {
@@ -58,6 +65,9 @@ enum parse_flags {
58
65
PF_RETURN ,
59
66
PF_WHILE ,
60
67
PF_ADVANCE , // used to report that although index was not changed, rule is suppose to advance
68
+ PF_COLLECT ,
69
+ PF_KEEP ,
70
+ PF_PICK ,
61
71
};
62
72
63
73
#define MAX_PARSE_DEPTH 512
@@ -83,7 +93,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
83
93
84
94
/***********************************************************************
85
95
**
86
- */ static REBCNT Parse_Series (REBVAL * val , REBVAL * rules , REBCNT flags , REBCNT depth )
96
+ */ static REBCNT Parse_Series (REBVAL * val , REBVAL * rules , REBCNT flags , REBCNT depth , REB_PARSE_COLLECT * collect )
87
97
/*
88
98
***********************************************************************/
89
99
{
@@ -93,6 +103,8 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
93
103
parse .type = VAL_TYPE (val );
94
104
parse .flags = flags ;
95
105
parse .result = 0 ;
106
+ //parse.retval = NULL;
107
+ parse .collect = collect ;
96
108
97
109
return Parse_Rules_Loop (& parse , VAL_INDEX (val ), rules , depth );
98
110
}
@@ -655,6 +667,93 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
655
667
}
656
668
#endif // USE_DO_PARSE_RULE
657
669
670
+ /***********************************************************************
671
+ **
672
+ */ static REBSER * Parse_Collect_Block (REBPARSE * parse )
673
+ /*
674
+ ***********************************************************************/
675
+ {
676
+ REBVAL * val ;
677
+ if (parse -> collect -> depth == 0 ) Trap0 (RE_PARSE_NO_COLLECT );
678
+
679
+ if (!parse -> collect -> block ) {
680
+ // there is no yet allocated block for collection
681
+ // but the parent is on top of the stack, so we can
682
+ // allocate a new block for the keep.
683
+ val = DS_TOP ;
684
+ val = Append_Value (VAL_SERIES (val ));
685
+ Set_Series (REB_BLOCK , val , Make_Block (2 ));
686
+ // and mark it for use
687
+ parse -> collect -> block = VAL_SERIES (val );
688
+ }
689
+ return parse -> collect -> block ;
690
+ }
691
+
692
+ /***********************************************************************
693
+ **
694
+ */ static void Parse_Keep (REBPARSE * parse , REBSER * series , REBCNT begin , REBCNT count , REBOOL pick )
695
+ /*
696
+ ***********************************************************************/
697
+ {
698
+ REBVAL * val ;
699
+ REBINT i , e ;
700
+ REBSER * block = Parse_Collect_Block (parse );
701
+
702
+ ASSERT1 (block , RP_MISC ); // should never happen
703
+
704
+ if (parse -> collect -> depth == 0 ) Trap0 (RE_PARSE_NO_COLLECT );
705
+
706
+ //printf("Keep from %i count: %i to: %x\n", begin, count, block);
707
+
708
+ if (count > 1 ) {
709
+
710
+ if (IS_BLOCK_INPUT (parse )) {
711
+ if (pick ) {
712
+ Insert_Series (block , AT_TAIL , SERIES_SKIP (series , begin ), count );
713
+ }
714
+ else {
715
+ val = Append_Value (block );
716
+ Set_Block (val , Copy_Block_Len (series , begin , count ));
717
+ }
718
+ }
719
+ else {
720
+ if (pick ) {
721
+ e = begin + count ;
722
+ if (parse -> type == REB_BINARY ) {
723
+ for (i = begin ; i < e ; i ++ ) {
724
+ val = Append_Value (block );
725
+ SET_INTEGER (val , BIN_HEAD (series )[i ]);
726
+ }
727
+ }
728
+ else {
729
+ for (i = begin ; i < e ; i ++ ) {
730
+ val = Append_Value (block );
731
+ SET_CHAR (val , GET_ANY_CHAR (series , i ));
732
+ }
733
+ }
734
+ }
735
+ else {
736
+ val = Append_Value (block );
737
+ VAL_SERIES (val ) = Copy_String (series , begin , count );
738
+ VAL_INDEX (val ) = 0 ;
739
+ VAL_SET (val , parse -> type );
740
+ }
741
+ }
742
+ }
743
+ else if (count == 1 ) {
744
+ val = Append_Value (block );
745
+ if (IS_BLOCK_INPUT (parse )) {
746
+ * val = * BLK_SKIP (series , begin );
747
+ }
748
+ else if (parse -> type == REB_BINARY ) {
749
+ SET_INTEGER (val , BIN_HEAD (series )[begin ]);
750
+ }
751
+ else {
752
+ SET_CHAR (val , GET_ANY_CHAR (series , begin ));
753
+ }
754
+ }
755
+ }
756
+
658
757
/***********************************************************************
659
758
**
660
759
*/ static REBCNT Parse_Rules_Loop (REBPARSE * parse , REBCNT index , REBVAL * rules , REBCNT depth )
@@ -676,6 +775,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
676
775
REBSER * ser ;
677
776
REBFLG flags ;
678
777
REBCNT cmd ;
778
+ REBSER * blk ;
679
779
//REBVAL *rule_head = rules;
680
780
681
781
CHECK_STACK (& flags );
@@ -766,6 +866,52 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
766
866
SET_FLAG (flags , PF_CHANGE );
767
867
continue ;
768
868
869
+ case SYM_COLLECT :
870
+ if (IS_END (rules ))
871
+ Trap1 (RE_PARSE_END , rules - 1 );
872
+ //printf("COLLECT start %i\n", parse->collect->depth);
873
+ // reserve a new value on stack
874
+ DS_PUSH_NONE ;
875
+ if (parse -> collect -> block == NULL ) {
876
+ // --- FIRST collect -------------------------
877
+ // allocate the resulting block on the stack, so it is GC safe
878
+ Set_Series (REB_BLOCK , DS_TOP , Make_Block (2 ));
879
+ parse -> collect -> result = DS_TOP ;
880
+ parse -> collect -> block = VAL_SERIES (DS_TOP );
881
+ } else {
882
+ // --- SUBSEQUENT collect ---------------------
883
+ // store current block on stack
884
+ Set_Series (REB_BLOCK , DS_TOP , parse -> collect -> block );
885
+ // do not allocate a new one, until it is needed, else
886
+ // there could be unwanted empty blocks like in case:
887
+ // parse [1][collect some [collect keep integer!]]
888
+ parse -> collect -> block = NULL ;
889
+ }
890
+ SET_FLAG (flags , PF_COLLECT );
891
+ parse -> collect -> depth ++ ;
892
+ continue ;
893
+
894
+ case SYM_KEEP :
895
+ if (IS_END (rules )) {
896
+ Trap1 (RE_PARSE_END , rules - 1 );
897
+ }
898
+ if (IS_WORD (rules ) && VAL_SYM_CANON (rules ) == SYM_PICK ) {
899
+ SET_FLAG (flags , PF_PICK );
900
+ rules ++ ;
901
+ if (IS_END (rules ))
902
+ Trap1 (RE_PARSE_END , rules - 2 );
903
+ }
904
+ if (IS_PAREN (rules )) {
905
+ blk = Parse_Collect_Block (parse );
906
+ item = Do_Block_Value_Throw (rules ); // might GC
907
+ Append_Val (blk , item );
908
+ rules ++ ;
909
+ continue ;
910
+ }
911
+ SET_FLAG (flags , PF_KEEP );
912
+
913
+ continue ;
914
+
769
915
case SYM_RETURN :
770
916
if (IS_PAREN (rules )) {
771
917
item = Do_Block_Value_Throw (rules ); // might GC
@@ -939,7 +1085,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
939
1085
val = BLK_SKIP (series , index );
940
1086
i = (
941
1087
(ANY_BINSTR (val ) || ANY_BLOCK (val ))
942
- && (Parse_Series (val , VAL_BLK_DATA (item ), parse -> flags , depth + 1 ) == VAL_TAIL (val ))
1088
+ && (Parse_Series (val , VAL_BLK_DATA (item ), parse -> flags , depth + 1 , & parse -> collect ) == VAL_TAIL (val ))
943
1089
) ? index + 1 : NOT_FOUND ;
944
1090
break ;
945
1091
#ifdef USE_DO_PARSE_RULE
@@ -999,7 +1145,13 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
999
1145
}
1000
1146
//if (i >= series->tail) { // OLD check: no more input
1001
1147
else {
1002
- if (count < mincount ) index = NOT_FOUND ; // was not enough
1148
+ if (count < mincount ) {
1149
+ index = NOT_FOUND ; // was not enough
1150
+ // Uncomment bellow code, to have result:
1151
+ // [? []] = parse ["a"][collect some [keep ('?) collect keep integer!]]
1152
+ // if (GET_FLAG(flags, PF_KEEP))
1153
+ // Parse_Collect_Block(parse);
1154
+ }
1003
1155
else if (i != NOT_FOUND ) index = i ;
1004
1156
// else keep index as is.
1005
1157
break ;
@@ -1035,6 +1187,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
1035
1187
}
1036
1188
else { // Success actions:
1037
1189
count = (begin > index ) ? 0 : index - begin ; // how much we advanced the input
1190
+ ser = NULL ;
1038
1191
if (GET_FLAG (flags , PF_COPY )) {
1039
1192
ser = (IS_BLOCK_INPUT (parse ))
1040
1193
? Copy_Block_Len (series , begin , count )
@@ -1060,6 +1213,35 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
1060
1213
}
1061
1214
}
1062
1215
}
1216
+ if (GET_FLAG (flags , PF_KEEP )) {
1217
+ if (ser && GET_FLAG (flags , PF_COPY )) {
1218
+ val = Append_Value (parse -> collect -> block );
1219
+ if (IS_BLOCK_INPUT (parse )) {
1220
+ Set_Block (val , ser );
1221
+ }
1222
+ else if (parse -> type == REB_BINARY ) {
1223
+ Set_Binary (val , ser );
1224
+ }
1225
+ else {
1226
+ VAL_SET (val , parse -> type );
1227
+ VAL_SERIES (val ) = ser ;
1228
+ VAL_INDEX (val ) = 0 ;
1229
+ VAL_SERIES_SIDE (val ) = 0 ;
1230
+ }
1231
+ }
1232
+ else {
1233
+ Parse_Keep (parse , series , begin , count , GET_FLAG (flags , PF_PICK ));
1234
+ }
1235
+ }
1236
+ if (GET_FLAG (flags , PF_COLLECT )) {
1237
+ // COLLECT ends
1238
+ // get the previous target block from the stack and use it
1239
+ val = DS_POP ;
1240
+ parse -> collect -> block = VAL_SERIES (val );
1241
+ parse -> collect -> depth -- ;
1242
+ //printf("COLLECT done %i\n", parse->collect->depth);
1243
+ }
1244
+
1063
1245
if (GET_FLAG (flags , PF_RETURN )) {
1064
1246
ser = (IS_BLOCK_INPUT (parse ))
1065
1247
? Copy_Block_Len (series , begin , count )
@@ -1309,6 +1491,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
1309
1491
#endif
1310
1492
REBCNT n ;
1311
1493
REBOL_STATE state ;
1494
+ REB_PARSE_COLLECT collect ;
1312
1495
// Let user RETURN and THROW out of the PARSE. All other errors should relay.
1313
1496
PUSH_STATE (state , Saved_State );
1314
1497
if (SET_JUMP (state )) {
@@ -1328,8 +1511,17 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
1328
1511
Throw_Error (VAL_ERR_OBJECT (DS_RETURN ));
1329
1512
}
1330
1513
SET_STATE (state , Saved_State );
1331
- n = Parse_Series (val , VAL_BLK_DATA (arg ), (opts & PF_CASE ) ? AM_FIND_CASE : 0 , 0 );
1332
- SET_LOGIC (DS_RETURN , n >= VAL_TAIL (val ) && n != NOT_FOUND );
1514
+ collect .depth = 0 ;
1515
+ collect .result = NULL ;
1516
+ collect .block = NULL ;
1517
+
1518
+ n = Parse_Series (val , VAL_BLK_DATA (arg ), (opts & PF_CASE ) ? AM_FIND_CASE : 0 , 0 , & collect );
1519
+ if (collect .result ) {
1520
+ * D_RET = * collect .result ;
1521
+ }
1522
+ else {
1523
+ SET_LOGIC (DS_RETURN , n >= VAL_TAIL (val ) && n != NOT_FOUND );
1524
+ }
1333
1525
POP_STATE (state , Saved_State );
1334
1526
#ifdef INCLUDE_PARSE_SERIES_SPLITTING
1335
1527
}
0 commit comments