Skip to content

Instantly share code, notes, and snippets.

@masak
Created April 14, 2014 06:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save masak/10620845 to your computer and use it in GitHub Desktop.
Save masak/10620845 to your computer and use it in GitHub Desktop.
Simulating CPS in Perl 6 - code that can be paused and resumed in the middle
## Test
my $point_1_reached = False;
my $point_2_reached = False;
my $point_3_reached = False;
class Event1 {}
class Event2 {}
class Event3 {}
my $workflow = q[[[
expect Event1;
$point_1_reached = True;
expect Event2;
$point_2_reached = True;
expect Event3;
$point_3_reached = True;
]]];
register($workflow);
use Test;
ok not($point_1_reached), "no code run yet";
broadcast(Event1);
ok $point_1_reached, "point 1 reached...";
ok not $point_2_reached, "...but not point 2 yet";
broadcast(Event2);
ok $point_2_reached, "point 2 reached...";
ok not $point_3_reached, "...but not point 3 yet";
broadcast(Event3);
ok $point_3_reached, "point 3 reached";
done;
## Implementation
my %listeners;
sub register($workflow) {
my grammar Workflow {
regex TOP { <immediate> <delayed>? }
regex immediate {
<expect>
<statements>
}
regex delayed {
<expect>
(.*)
}
regex expect { \s* 'expect' \s* (\w+) \s* ';' }
regex statements { [<!before <expect>> .]* }
}
die "Could not parse: $workflow"
unless Workflow.parse($workflow);
my $body = ~$<immediate><statements>;
my $unevaluated_part = "";
if $<delayed> {
sub escape($s) { $s.subst(/\'/, q[\\'], :g) }
my $remaining_workflow = ~$<delayed>;
my $escaped = escape( $remaining_workflow );
$unevaluated_part = qq[; register('$escaped')];
}
my $fn_str = 'sub {' ~ $body ~ $unevaluated_part ~ '}';
my $fn = EVAL($fn_str);
my $event = EVAL(~$<immediate><expect>[0]);
%listeners{$event.WHICH} = $fn;
}
sub broadcast($event) {
my $listener = %listeners{$event.WHICH};
if $listener {
$listener();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment