Skip to content

Commit

Permalink
Return PARSE to TRUE/FALSE, elaborate /? names
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
hostilefork committed Jul 3, 2016
1 parent 2c7d58f commit 18a8030
Show file tree
Hide file tree
Showing 13 changed files with 103 additions and 170 deletions.
1 change: 0 additions & 1 deletion src/boot/errors.r
Expand Up @@ -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?)}
Expand Down
2 changes: 1 addition & 1 deletion src/core/c-eval.c
Expand Up @@ -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));

Expand Down
2 changes: 1 addition & 1 deletion src/core/m-gc.c
Expand Up @@ -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
Expand Down
82 changes: 39 additions & 43 deletions src/core/n-control.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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"
// ]
//
Expand All @@ -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
//
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -765,7 +765,7 @@ REBNATIVE(catch)
}
}

if (REF(q)) return R_TRUE;
if (REF(caught_q)) return R_TRUE;

return R_OUT;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}


Expand All @@ -1391,7 +1387,7 @@ static REB_R If_Unless_Core(struct Reb_Frame *frame_, REBOOL trigger) {
// branch ; [<opt> any-value!]
// /only
// "Return block branches literally instead of evaluating them."
// /?
// /branched?
// "Instead of branch result, return LOGIC! of if branch was taken"
// ]
//
Expand All @@ -1410,7 +1406,7 @@ REBNATIVE(if)
// branch ; [<opt> any-value!]
// /only
// "Return block branches literally instead of evaluating them."
// /?
// /branched?
// "Instead of branch result, return TRUE? if branch was taken"
// ]
//
Expand Down Expand Up @@ -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"
// ]
//
Expand All @@ -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`
Expand Down Expand Up @@ -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:
Expand All @@ -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"
// ]
//
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -1763,15 +1759,15 @@ REBNATIVE(trap)
return R_OUT_IS_THROWN;
}

if (REF(q)) return R_TRUE;
if (REF(trapped_q)) return R_TRUE;

return R_OUT;
}

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;
Expand All @@ -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;
}
14 changes: 7 additions & 7 deletions src/core/n-loop.c
Expand Up @@ -1146,18 +1146,18 @@ REBNATIVE(until)
//
// condition [block!]
// body [block!]
// /?
// /looped?
// "Instead of last body result, return LOGIC! of if body ever ran"
// ]
//
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))) {
Expand All @@ -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;
Expand Down

0 comments on commit 18a8030

Please sign in to comment.