[Nickle]Prototype implementation of twixt in nickle
Keith Packard
keithp@keithp.com
Sun, 04 Mar 2001 15:42:36 -0800
This is a multipart MIME message.
--==_Exmh_-3164320800
Content-Type: text/plain; charset=us-ascii
Here's a prototype of how continuations and twixt blocks work together
To recap the syntax:
twixt (enter; leave) body [ else failure ]
If 'enter' returns True, execute 'body' followed by 'leave'
else execute 'failure'
Ensure that any flow of control transfer from inside 'body' to
outside the twixt passes through 'leave'
Ensure that any flow of control transfer from outside 'twixt' to
inside 'body' passes through 'enter'
The basic plan is:
Jumping from 'l' to 'e'
Find deepest common parent 'p' of 'l' and 'e' in the twixt chain
'leave' all twixt blocks between 'l' and 'p'
'enter' all twixt blocks between 'p' and 'e'
Pick up execution at 'e'
One complicating factor -- 'enter' blocks may fail, at which point the
'else' clause in the twixt is executed and execution picks up from there.
First-class continuations really help out here.
-keith
--==_Exmh_-3164320800
Content-Type: text/plain ; name="twixt.5c"; charset=us-ascii
Content-Description: twixt.5c
Content-Disposition: attachment; filename="twixt.5c"
typedef struct {
poly next;
integer depth;
integer(continuation c) enter;
poly(continuation c) leave;
} chain;
typedef struct {
continuation cont;
*chain list;
} do_continue;
*chain list;
do_continue nested;
function chain_depth (*chain c)
{
if (c)
return c->depth;
else
return 0;
}
function do_jump (do_continue enter, poly value)
{
*chain l, e;
*chain l_parent, e_parent;
continuation c;
integer i;
printf ("do_jump\n");
l = list;
e = enter.list;
l_parent = l;
e_parent = e;
/*
* Make both lists the same length
*/
i = chain_depth(l) - chain_depth (e);
if (i >= 0)
while (i-- > 0)
l_parent = l_parent->next;
else
while (i++ < 0)
e_parent = e_parent->next;
/*
* Now find the common parent
*/
while (l_parent != e_parent)
{
l_parent = l_parent->next;
e_parent = e_parent->next;
}
/*
* Unwind the twixt blocks in the source list
*/
function do_leave (*chain l)
{
if (l != l_parent)
{
if (set_jump (&c, 0) == 0)
{
printf ("calling leave\n");
l->leave (c);
}
do_leave (l->next);
}
}
/*
* Rewind the twixt blocks in the target list
*/
function do_enter (*chain e)
{
if (e != e_parent)
{
do_enter (e->next);
if (set_jump (&c, 0) == 0)
{
printf ("calling enter\n");
e->enter (c);
}
}
}
do_leave (l);
do_enter (e);
long_jump (enter.cont, value);
}
poly function do_set (*do_continue target, poly value)
{
*target = do_continue { list = list };
return set_jump (&target->cont, value);
}
function do_twixt (integer () enter, poly() leave,
poly() body, poly() else_)
{
continuation c_enter;
continuation c_leave;
continuation c_else;
chain l;
integer function f_enter (continuation c)
{
printf ("f_enter\n");
if (enter())
{
printf ("f_enter jumping normal\n");
long_jump (c, 1);
}
else
{
printf ("f_enter jumping fail\n");
long_jump (c_else, 1);
}
}
function f_leave (continuation c)
{
printf ("f_leave\n");
leave();
long_jump (c, 1);
}
if (set_jump (&c_else, 0) == 0)
{
if (set_jump (&c_enter, 0) == 0)
{
f_enter (c_enter);
}
else if (set_jump (&c_leave, 0) == 0)
{
chain l;
l = chain { next = list, enter = f_enter, leave = f_leave };
if (list)
l.depth = list->depth + 1;
else
l.depth = 1;
list = &l;
printf ("before body\n");
body ();
printf ("after body\n");
f_leave (c_leave);
}
}
else
{
printf ("else\n");
else_();
}
}
function body (do_continue jump)
{
printf ("body\n");
if (do_set (&nested, 0) == 0)
{
printf ("jumping\n");
do_jump (jump, 1);
}
else
{
printf ("re-entered body\n");
printf ("returning\n");
}
}
integer critical_value = 1;
function critical (do_continue jump)
{
printf ("critical enter\n");
do_twixt (integer func ()
{
printf ("enter lambda\n");
return critical_value;
},
func ()
{
printf ("leave lambda\n");
},
func ()
{
printf ("body lambda\n");
body (jump);
},
func ()
{
printf ("else lambda\n");
});
printf ("critical done\n");
}
function start ()
{
do_continue c;
printf ("start\n");
if (do_set (&c, 0) == 0)
{
critical (c);
printf ("back from critical\n");
}
else
{
printf ("back from do_jump\n");
}
printf ("start done\n");
}
--==_Exmh_-3164320800--