aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeddy <ted.sybil@gmail.com>2013-08-15 11:17:09 +0800
committerTeddy <ted.sybil@gmail.com>2013-08-15 11:17:09 +0800
commitbe799b976d6fd58960d0a44e0f389c8f6765e7c0 (patch)
treefc31e822253cc3bdc6aaed1043819b32c95efd5d
parent9f9bd0ee34422aceb9725276292a66b0e7934c6a (diff)
tail-rec support for `or`
-rw-r--r--builtin.cpp47
1 files changed, 35 insertions, 12 deletions
diff --git a/builtin.cpp b/builtin.cpp
index 47fdda8..98e7bbc 100644
--- a/builtin.cpp
+++ b/builtin.cpp
@@ -448,26 +448,40 @@ void SpecialOptOr::prepare(Pair *pc) {
Pair *SpecialOptOr::call(Pair *args, Environment * &lenvt,
Continuation * &cont, EvalObj ** &top_ptr, Pair *pc) {
Pair *ret_addr = cont->pc;
- if (pc->cdr == empty_list)
+ Pair *cs = cont->state;
+ Pair *nexp;
+ if (pc->cdr == empty_list) // empty list
{
gc.expose(*top_ptr);
*top_ptr++ = gc.attach(new BoolObj(false));
EXIT_CURRENT_EXEC(lenvt, cont, args);
return ret_addr->next;
}
- if (!cont->state)
+ if (!cs) // spawn the first
{
- gc.attach(static_cast<EvalObj*>(*(++top_ptr)));
- top_ptr++;
- cont->state = TO_PAIR(pc->cdr);
- cont->state->next = NULL;
- gc.expose(args);
- return cont->state;
+ nexp = cont->state = TO_PAIR(pc->cdr);
+ if (nexp->cdr == empty_list && !nexp->car->is_simple_obj())
+ {
+ cont->tail = true;
+ cont->state = NULL;
+ top_ptr++;
+ gc.expose(args);
+ return nexp;
+ }
+ else
+ {
+ gc.attach(static_cast<EvalObj*>(*(++top_ptr)));
+ top_ptr++;
+ nexp->next = NULL;
+ gc.expose(args);
+ return nexp;
+ }
}
+
EvalObj *ret = TO_PAIR(args->cdr)->car;
if (!ret->is_true())
{
- if (cont->state->cdr == empty_list) // the last member
+ if (cs->cdr == empty_list) // the last member
{
gc.expose(*top_ptr);
*top_ptr++ = gc.attach(ret);
@@ -476,12 +490,21 @@ Pair *SpecialOptOr::call(Pair *args, Environment * &lenvt,
}
else
{
+ nexp = TO_PAIR(cs->cdr);
+ if (nexp->cdr == empty_list && !nexp->car->is_simple_obj())
+ {
+ cont->tail = true;
+ cont->state = NULL;
+ top_ptr++;
+ gc.expose(args);
+ return nexp;
+ }
gc.attach(static_cast<EvalObj*>(*(++top_ptr)));
top_ptr++;
- cont->state = TO_PAIR(cont->state->cdr);
- cont->state->next = NULL;
+ nexp = cont->state = TO_PAIR(cont->state->cdr);
+ nexp->next = NULL;
gc.expose(args);
- return cont->state;
+ return nexp;
}
}
else