From 18a8030a3d579e2a7e3dde12a49335969aaf631f Mon Sep 17 00:00:00 2001 From: Hostile Fork Date: Sun, 3 Jul 2016 08:54:33 -0400 Subject: [PATCH] Return PARSE to TRUE/FALSE, elaborate /? names An experiment was run for a while which would return the input from PARSE if it matched (instead of just TRUE) and then blank if it did not match (instead of FALSE). Then a PARSE? was offered that would do only TRUE and FALSE results, limiting the return results to that if someone tried to use a RETURN instruction inside the PARSE. This was tried before CHAIN and the other function composers, so it resulted in a duplication of PARSE's interface. The idea had a bit of an ergonomic problem in that it made the results of PARSE harder to understand than TRUE/FALSE in the common case. Given COLLECT as a future possible direction, it may also confuse matters further. Additionally, the usefulness of a return result the caller already has is likely a poor choice...better would be something that parse knows (e.g. the position of a failure). This uses CHAIN to make a checking version to enforce the TRUE/FALSE result, and restores the common baseline of TRUE and FALSE until more thinking has been put into it. It also removes /ALL from the non compatibility PARSE. This also takes the other /? refinements for functions and gives them more descriptive names. --- src/boot/errors.r | 1 - src/core/c-eval.c | 2 +- src/core/m-gc.c | 2 +- src/core/n-control.c | 82 ++++++++++++++++----------------- src/core/n-loop.c | 14 +++--- src/core/u-parse.c | 92 +++++++------------------------------- src/include/sys-action.h | 9 ++-- src/mezz/base-funcs.r | 31 ++++++++++--- src/tools/common-parsers.r | 8 ++-- src/tools/make-reb-lib.r | 20 --------- tests/lib/text-lines.reb | 6 +-- tests/misc/unzip.reb | 2 +- tests/source-tools.reb | 4 +- 13 files changed, 103 insertions(+), 170 deletions(-) diff --git a/src/boot/errors.r b/src/boot/errors.r index 46620f1496..11df96eb3d 100644 --- a/src/boot/errors.r +++ b/src/boot/errors.r @@ -215,7 +215,6 @@ Script: [ parse-variable: [{PARSE - expected a variable, not:} :arg1] parse-command: [{PARSE - command cannot be used as variable:} :arg1] parse-series: [{PARSE - input must be a series:} :arg1] - parse-non-logic: [{Non-logic PARSE? result:} :arg1 {use PARSE instead}] not-ffi-build: {This Rebol build wasn't linked with libffi features} bad-library: {bad library (already closed?)} diff --git a/src/core/c-eval.c b/src/core/c-eval.c index f0fd2a7535..22cf704357 100644 --- a/src/core/c-eval.c +++ b/src/core/c-eval.c @@ -1463,7 +1463,7 @@ void Do_Core(struct Reb_Frame * const f) // includes argument arrays being fulfilled). This offers extra // perks, because it means a recycle/torture will catch you if you // try to Do_Core into movable memory...*and* a native can tell if it - // has written the output slot yet or not (e.g. WHILE's /? refinement). + // has written the out slot yet or not (e.g. WHILE/LOOPED? refinement). // assert(IS_END(f->out)); diff --git a/src/core/m-gc.c b/src/core/m-gc.c index f7cdb6cd23..e9367053ab 100755 --- a/src/core/m-gc.c +++ b/src/core/m-gc.c @@ -1230,7 +1230,7 @@ ATTRIBUTE_NO_SANITIZE_ADDRESS static void Mark_Root_Series(void) // MARK_REBSER(s); Queue_Mark_Value_Deep(key); - Queue_Mark_Value_Deep(pairing); + Queue_Mark_Value_Deep(pairing); // allow END? } else { // We have to do the queueing based on whatever type of series diff --git a/src/core/n-control.c b/src/core/n-control.c index 1d3dd5fa7e..5386edfa1a 100755 --- a/src/core/n-control.c +++ b/src/core/n-control.c @@ -489,15 +489,15 @@ REBNATIVE(break) // "Block of cases (conditions followed by values)" // /all // {Evaluate all cases (do not stop at first TRUE? case)} -// /? -// "Instead of last case result, return LOGIC! of if any case matched" +// /ran? +// "Instead of last case result, return LOGIC! of if any cases ran" // ] // REBNATIVE(case) { PARAM(1, block); REFINE(2, all_reused); - REFINE(3, q); + REFINE(3, ran_q); REBOOL all = REF(all_reused); REBVAL *temp = ARG(all_reused); // temporary value, GC safe (if needed) @@ -571,11 +571,11 @@ REBNATIVE(case) //return_maybe_matched: DROP_SAFE_ENUMERATOR(&e); - return R_OUT_Q(REF(q)); // reacts if /?, detects if D_OUT was written to + return R_OUT_Q(REF(ran_q)); // if /ran?, detect if D_OUT was written to return_matched: DROP_SAFE_ENUMERATOR(&e); - if (REF(q)) return R_TRUE; // at least one case ran for /? to get TRUE + if (REF(ran_q)) return R_TRUE; // /ran? gets TRUE if at least one case ran return R_OUT; return_thrown: @@ -603,7 +603,7 @@ REBNATIVE(case) // "Handle thrown case with code" // handler [block! function!] // "If FUNCTION!, spec matches [value name]" -// /? +// /caught? // "Instead of result or catch, return LOGIC! of if a catch occurred" // ] // @@ -620,7 +620,7 @@ REBNATIVE(catch) REFINE(5, any); REFINE(6, with); PARAM(7, handler); - REFINE(8, q); + REFINE(8, caught_q); // /ANY would override /NAME, so point out the potential confusion // @@ -697,7 +697,7 @@ REBNATIVE(catch) return R_OUT_IS_THROWN; } - if (REF(q)) return R_FALSE; + if (REF(caught_q)) return R_FALSE; return R_OUT; @@ -721,7 +721,7 @@ REBNATIVE(catch) if (DO_VAL_ARRAY_AT_THROWS(D_OUT, ARG(handler))) return R_OUT_IS_THROWN; - if (REF(q)) return R_TRUE; + if (REF(caught_q)) return R_TRUE; return R_OUT; } @@ -765,7 +765,7 @@ REBNATIVE(catch) } } - if (REF(q)) return R_TRUE; + if (REF(caught_q)) return R_TRUE; return R_OUT; } @@ -775,7 +775,7 @@ REBNATIVE(catch) // CATCH_THROWN(D_OUT, D_OUT); - if (REF(q)) return R_TRUE; + if (REF(caught_q)) return R_TRUE; return R_OUT; } @@ -1353,32 +1353,28 @@ static REB_R If_Unless_Core(struct Reb_Frame *frame_, REBOOL trigger) { PARAM(1, condition); PARAM(2, branch); REFINE(3, only); - REFINE(4, q); // actually "?" - return TRUE if branch taken, else FALSE + REFINE(4, branched_q); // return TRUE if branch taken, else FALSE - assert((trigger == TRUE) || (trigger == FALSE)); + if (IS_CONDITIONAL_TRUE(ARG(condition)) != trigger) { // don't take branch + if (REF(branched_q)) + return R_FALSE; + return R_VOID; + } - if (IS_CONDITIONAL_TRUE(ARG(condition)) == trigger) { - if (REF(only) || !IS_BLOCK(ARG(branch))) { - if (!REF(q)) { - *D_OUT = *ARG(branch); - return R_OUT; - } + if (REF(only) || !IS_BLOCK(ARG(branch))) { // taking, but no code to run! + if (REF(branched_q)) return R_TRUE; - } - - if (DO_VAL_ARRAY_AT_THROWS(D_OUT, ARG(branch))) - return R_OUT_IS_THROWN; - - if (!REF(q)) - return R_OUT; - - return R_TRUE; + *D_OUT = *ARG(branch); + return R_OUT; } - if (!REF(q)) - return R_VOID; + // Take branch and evaluate block - return R_FALSE; + if (DO_VAL_ARRAY_AT_THROWS(D_OUT, ARG(branch))) + return R_OUT_IS_THROWN; + if (REF(branched_q)) + return R_TRUE; + return R_OUT; } @@ -1391,7 +1387,7 @@ static REB_R If_Unless_Core(struct Reb_Frame *frame_, REBOOL trigger) { // branch ; [ any-value!] // /only // "Return block branches literally instead of evaluating them." -// /? +// /branched? // "Instead of branch result, return LOGIC! of if branch was taken" // ] // @@ -1410,7 +1406,7 @@ REBNATIVE(if) // branch ; [ any-value!] // /only // "Return block branches literally instead of evaluating them." -// /? +// /branched? // "Instead of branch result, return TRUE? if branch was taken" // ] // @@ -1570,7 +1566,7 @@ REBNATIVE(leave) // "Evaluate all matches (not just first one)" // /strict // {Use STRICT-EQUAL? when comparing cases instead of EQUAL?} -// /? +// /matched? // "Instead of last case result, return LOGIC! of if any case matched" // ] // @@ -1582,7 +1578,7 @@ REBNATIVE(switch) PARAM(4, default_case); REFINE(5, all); REFINE(6, strict); - REFINE(7, q); + REFINE(7, matched_q); Reb_Enumerator e; PUSH_SAFE_ENUMERATOR(&e, ARG(cases)); // DO-ing matches may disrupt `cases` @@ -1683,12 +1679,12 @@ REBNATIVE(switch) //return_defaulted: DROP_SAFE_ENUMERATOR(&e); - if (REF(q)) return R_FALSE; // running default code doesn't count for /? + if (REF(matched_q)) return R_FALSE; // default code doesn't /matched? count return R_OUT; return_matched: DROP_SAFE_ENUMERATOR(&e); - if (REF(q)) return R_TRUE; + if (REF(matched_q)) return R_TRUE; return R_OUT; return_thrown: @@ -1707,7 +1703,7 @@ REBNATIVE(switch) // "Handle error case with code" // handler [block! function!] // "If FUNCTION!, spec allows [error [error!]]" -// /? +// /trapped? // "Instead of result or error, return LOGIC! of if a trap occurred" // ] // @@ -1716,7 +1712,7 @@ REBNATIVE(trap) PARAM(1, block); REFINE(2, with); PARAM(3, handler); - REFINE(4, q); + REFINE(4, trapped_q); struct Reb_State state; REBCTX *error; @@ -1735,7 +1731,7 @@ REBNATIVE(trap) if (DO_VAL_ARRAY_AT_THROWS(D_OUT, ARG(handler))) return R_OUT_IS_THROWN; - if (REF(q)) return R_TRUE; + if (REF(trapped_q)) return R_TRUE; return R_OUT; } @@ -1763,7 +1759,7 @@ REBNATIVE(trap) return R_OUT_IS_THROWN; } - if (REF(q)) return R_TRUE; + if (REF(trapped_q)) return R_TRUE; return R_OUT; } @@ -1771,7 +1767,7 @@ REBNATIVE(trap) panic (Error(RE_MISC)); // should not be possible (type-checking) } - if (REF(q)) return R_TRUE; + if (REF(trapped_q)) return R_TRUE; Val_Init_Error(D_OUT, error); return R_OUT; @@ -1795,7 +1791,7 @@ REBNATIVE(trap) DROP_TRAP_SAME_STACKLEVEL_AS_PUSH(&state); - if (REF(q)) return R_FALSE; + if (REF(trapped_q)) return R_FALSE; return R_OUT; } diff --git a/src/core/n-loop.c b/src/core/n-loop.c index c4e90ddf1d..057ad33b45 100755 --- a/src/core/n-loop.c +++ b/src/core/n-loop.c @@ -1146,7 +1146,7 @@ REBNATIVE(until) // // condition [block!] // body [block!] -// /? +// /looped? // "Instead of last body result, return LOGIC! of if body ever ran" // ] // @@ -1154,10 +1154,10 @@ REBNATIVE(while) { PARAM(1, condition); PARAM(2, body); - REFINE(3, q_reused); + REFINE(3, looped_q_reused); - REBOOL q = VAL_LOGIC(ARG(q_reused)); - REBVAL *temp = ARG(q_reused); // cell-sized slot that is also GC-safe + REBOOL looped_q = VAL_LOGIC(ARG(looped_q_reused)); + REBVAL *temp = ARG(looped_q_reused); // cell-sized slot taken for GC safety do { if (DO_VAL_ARRAY_AT_THROWS(temp, ARG(condition))) { @@ -1175,16 +1175,16 @@ REBNATIVE(while) fail (Error(RE_NO_RETURN)); if (IS_CONDITIONAL_FALSE(temp)) - return R_OUT_Q(q); + return R_OUT_Q(looped_q); // If this line runs, it will put a non-END marker in D_OUT, which - // will signal R_OUT_Q() to return TRUE if /? (and D_OUT otherwise) + // will signal R_OUT_Q() to TRUE if /looped? (and D_OUT otherwise) // if (DO_VAL_ARRAY_AT_THROWS(D_OUT, ARG(body))) { REBOOL stop; if (Catching_Break_Or_Continue(D_OUT, &stop)) { if (stop) { - if (q) return R_TRUE; + if (looped_q) return R_TRUE; return R_OUT; } continue; diff --git a/src/core/u-parse.c b/src/core/u-parse.c index df84bc5947..8ea07940f8 100755 --- a/src/core/u-parse.c +++ b/src/core/u-parse.c @@ -2149,17 +2149,23 @@ REBNATIVE(subparse) // -// Shared implementation routine for PARSE? and PARSE. The difference is that -// PARSE? only returns whether or not a set of rules completed to the end. -// PARSE is more general purpose in terms of the result it provides, and -// it defaults to returning the input. +// parse: native [ +// +// "Parses a series according to grammar rules and returns a result." // -static REB_R Parse_Core(struct Reb_Frame *frame_, REBOOL logic) +// input [any-series!] +// "Input series to parse (default result for successful match)" +// rules [block! string! blank!] +// "Rules to parse by (STRING! and BLANK!/none! are deprecated)" +// /case +// "Uses case-sensitive comparison" +// ] +// +REBNATIVE(parse) { PARAM(1, input); PARAM(2, rules); REFINE(3, case); - REFINE(4, all); REBVAL *rules = ARG(rules); REBCNT index; @@ -2214,20 +2220,6 @@ static REB_R Parse_Core(struct Reb_Frame *frame_, REBOOL logic) // This handles that branch and catches the result value. // CATCH_THROWN(D_OUT, D_OUT); - - // In the logic case, we are only concerned with matching. If - // a construct that can return arbitrary values is used, then - // failure is triggered with a specific error, saying PARSE must - // be used instead of PARSE?. - // - // !!! Review if this is the best semantics for a parsing variant - // that is committed to only returning logic TRUE or FALSE, in - // spite of existence of rules that allow the general PARSE to - // do otherwise. - // - if (logic && !IS_LOGIC(D_OUT)) - fail (Error(RE_PARSE_NON_LOGIC, D_OUT)); - return R_OUT; } @@ -2239,7 +2231,7 @@ static REB_R Parse_Core(struct Reb_Frame *frame_, REBOOL logic) // Parse can fail if the match rule state can't process pending input. // if (IS_BLANK(D_OUT)) - return logic ? R_FALSE : R_BLANK; + return R_FALSE; assert(IS_INTEGER(D_OUT)); @@ -2247,63 +2239,11 @@ static REB_R Parse_Core(struct Reb_Frame *frame_, REBOOL logic) // at (or beyond) the tail of the input series, the parse also failed. // if (VAL_UNT32(D_OUT) < VAL_LEN_HEAD(ARG(input))) - return logic ? R_FALSE : R_BLANK; + return R_FALSE; - // The end was reached...if doing a logic-based PARSE? then return TRUE. + // The end was reached. Return TRUE. (Alternate thoughts, see #2165) // - if (logic) return R_TRUE; - - // Otherwise it's PARSE so return the input (a series, hence conditionally - // true, yet more informative for chaining.) See #2165. - // - *D_OUT = *ARG(input); - return R_OUT; -} - - -// -// parse?: native [ -// -// ; NOTE: If changing this, also update PARSE -// -// "Determines if a series matches the given grammar rules or not." -// -// input [any-series!] -// "Input series to parse" -// rules [block! string! blank!] -// "Rules to parse by (STRING! and BLANK!/none! are deprecated)" -// /case -// "Uses case-sensitive comparison" -// /all -// "(ignored refinement left for Rebol2 transitioning)" -// ] -// -REBNATIVE(parse_q) -{ - return Parse_Core(frame_, TRUE); -} - - -// -// parse: native [ -// -// ; NOTE: If changing this, also update PARSE? -// -// "Parses a series according to grammar rules and returns a result." -// -// input [any-series!] -// "Input series to parse (default result for successful match)" -// rules [block! string! blank!] -// "Rules to parse by (STRING! and NONE! are deprecated)" -// /case -// "Uses case-sensitive comparison" -// /all -// "(ignored refinement left for Rebol2 transitioning)" -// ] -// -REBNATIVE(parse) -{ - return Parse_Core(frame_, FALSE); + return R_TRUE; } diff --git a/src/include/sys-action.h b/src/include/sys-action.h index 3403879f78..5d102139d0 100644 --- a/src/include/sys-action.h +++ b/src/include/sys-action.h @@ -48,8 +48,8 @@ enum { // R_OUT_IS_THROWN, - // This is a return value in service of the /? functions. Since all - // dispatchers receive an END marker in the f->out slot (a.k.a. D_OUT) + // This is a return value in service of refinements like IF/BRANCHED?. + // Since all dispatchers get END markers in the f->out slot (a.k.a. D_OUT) // then it can be used to tell if the output has been written "in band" // by a legal value or void. This returns TRUE if D_OUT is not END, // and FALSE if it still is. @@ -83,8 +83,9 @@ enum { }; typedef REBCNT REB_R; -// Convenience function for getting the "/?" behavior if it is enabled, and -// doing the default thing--assuming END is being left in the D_OUT slot +// Convenience function for getting behaviors like WHILE/LOOPED?", and +// doing the default thing--assuming END is being left in the D_OUT slot if +// the tested-for condition is not met. // inline static REB_R R_OUT_Q(REBOOL q) { if (q) return R_OUT_TRUE_IF_WRITTEN; diff --git a/src/mezz/base-funcs.r b/src/mezz/base-funcs.r index b979ee0a3b..64e525518c 100644 --- a/src/mezz/base-funcs.r +++ b/src/mezz/base-funcs.r @@ -305,43 +305,43 @@ redescribe [ if?: redescribe [ {Variation of IF which returns TRUE if the branch runs, FALSE if not} ]( - specialize 'if [?: true] + specialize 'if [branched?: true] ) unless?: redescribe [ {Variation of UNLESS which returns TRUE if the branch runs, FALSE if not} ]( - specialize 'unless [?: true] + specialize 'unless [branched?: true] ) while?: redescribe [ {Variation of WHILE which returns TRUE if the body ever runs, FALSE if not} ]( - specialize 'while [?: true] + specialize 'while [looped?: true] ) case?: redescribe [ {Variation of CASE which returns TRUE if any cases run, FALSE if not} ]( - specialize 'case [?: true] + specialize 'case [ran?: true] ) switch?: redescribe [ {Variation of SWITCH which returns TRUE if any cases run, FALSE if not} ]( - specialize 'switch [?: true] + specialize 'switch [matched?: true] ) trap?: redescribe [ {Variation of TRAP which returns TRUE if an error traps, FALSE if not} ]( - specialize 'trap [?: true] + specialize 'trap [trapped?: true] ) catch?: redescribe [ {Variation of CATCH which returns TRUE if a throw is caught, FALSE if not} ]( - specialize 'catch [?: true] + specialize 'catch [caught?: true] ) any?: redescribe [ @@ -368,6 +368,23 @@ select?: redescribe [ chain [:select :any-value?] ) +parse?: redescribe [ + {Variant of PARSE that enforces a TRUE or FALSE result from the rules.} +]( + chain [ + :parse + | + func [x][ + unless logic? :x [ + fail [ + "Rules passed to PARSE? returned non-LOGIC!:" (mold :x) + ] + ] + ] + ] +) + + ; To help for discoverability, there is SET-INFIX and INFIX?. However, the ; term can be a misnomer if the function is more advanced, and using the ; "lookback" capabilities in another way. Hence these return descriptive diff --git a/src/tools/common-parsers.r b/src/tools/common-parsers.r index a12796c298..d18cb67cca 100644 --- a/src/tools/common-parsers.r +++ b/src/tools/common-parsers.r @@ -58,7 +58,7 @@ decode-key-value-text: function [ meta: make block! [] - if not parse/all text data-fields [ + if not parse text data-fields [ fail [ {Expected key value format on line} (line-of text position) {and lines must end with newline.} @@ -78,7 +78,7 @@ decode-lines: function [ pattern: compose/only [(line-prefix)] if not empty? indent [append pattern compose/only [opt (indent)]] line: [pos: pattern rest: (rest: remove/part pos rest) :rest thru newline] - if not parse/all text [any line] [ + if not parse text [any line] [ fail [ {Expected line} (line-of text pos) {to begin with} (mold line-prefix) @@ -129,7 +129,7 @@ line-of: function [ count-line: [(line: 1 + any [line 0])] - parse/all copy/part text next position [ + parse copy/part text next position [ any [to newline skip count-line] skip count-line ] @@ -256,7 +256,7 @@ proto-parser: context [ is-format201603-fileheader: parsing-at position [ either all [ lines: attempt [decode-lines lines {//} { }] - parse/all lines [copy data to {=///} to end] + parse lines [copy data to {=///} to end] data: attempt [load-until-blank trim/auto data] data: attempt [ either set-word? first data/1 [data/1][blank] diff --git a/src/tools/make-reb-lib.r b/src/tools/make-reb-lib.r index 7f39c9a627..d8beb68db8 100644 --- a/src/tools/make-reb-lib.r +++ b/src/tools/make-reb-lib.r @@ -230,26 +230,6 @@ form-header/gen "REBOL Host and Extension API" %reb-lib.r %make-reb-lib.r #define RL_REV } ver/2 { #define RL_UPD } ver/3 { -// Compatiblity with the lib requires that structs are aligned using the same -// method. This is concrete, not abstract. The macro below uses struct -// sizes to inform the developer that something is wrong. -#if defined(__LP64__) || defined(__LLP64__) - -#ifdef HAS_POSIX_SIGNAL - #define CHECK_STRUCT_ALIGN (sizeof(REBREQ) == 196 && sizeof(REBEVT) == 32) -#else - #define CHECK_STRUCT_ALIGN (sizeof(REBREQ) == 100 && sizeof(REBEVT) == 32) -#endif //HAS_POSIX_SIGNAL - -#else // !defined(__LP64__) && !defined(__LLP64__) - -#ifdef HAS_POSIX_SIGNAL - #define CHECK_STRUCT_ALIGN (sizeof(REBREQ) == 180 && sizeof(REBEVT) == 16) -#else - #define CHECK_STRUCT_ALIGN (sizeof(REBREQ) == 80 && sizeof(REBEVT) == 16) -#endif //HAS_POSIX_SIGNAL - -#endif // Function entry points for reb-lib (used for MACROS below):} rlib-buffer diff --git a/tests/lib/text-lines.reb b/tests/lib/text-lines.reb index c3c1ada956..1b06f4ad55 100644 --- a/tests/lib/text-lines.reb +++ b/tests/lib/text-lines.reb @@ -20,7 +20,7 @@ decode-lines: function [ line-prefix [string!] {Usually "**" or "//".} indent [string!] {Usually " ".} ] [ - if not parse/all text [any [line-prefix thru newline]] [ + if not parse text [any [line-prefix thru newline]] [ fail [{decode-lines expects each line to begin with} (mold line-prefix) { and finish with a newline.}] ] insert text newline @@ -98,7 +98,7 @@ lines-exceeding: function [ ) ] - parse/all text [ + parse text [ any [bol: to newline eol: skip count-line] bol: skip to end eol: count-line ] @@ -120,7 +120,7 @@ line-of: function [ count-line: [(line: 1 + any [line 0])] - parse/all copy/part text next position [ + parse copy/part text next position [ any [to newline skip count-line] skip count-line ] diff --git a/tests/misc/unzip.reb b/tests/misc/unzip.reb index 89ce2e1006..dd7300306a 100644 --- a/tests/misc/unzip.reb +++ b/tests/misc/unzip.reb @@ -316,7 +316,7 @@ ctx-zip: context [ ] if any-file? source [source: read source] nb-entries: 0 - parse/all source [ + parse source [ to local-file-sig some [ to local-file-sig 4 skip diff --git a/tests/source-tools.reb b/tests/source-tools.reb index e06e7324cf..aeac707a3b 100644 --- a/tests/source-tools.reb +++ b/tests/source-tools.reb @@ -120,7 +120,7 @@ rebsource: context [ malloc-check: [is-identifier "malloc" (append any [malloc malloc: copy []] line-of file-text position)] - parse/all/case file-text [ + parse/case file-text [ some [ position: malloc-check @@ -226,7 +226,7 @@ rebsource: context [ ] ] - remove-each file files [not parse/all file [thru {.c}]] + remove-each file files [not parse file [thru {.c}]] sort files files