Implement tagbody and go macros
This commit is contained in:
parent
44468958b6
commit
e6342eda24
2 changed files with 98 additions and 0 deletions
|
@ -479,6 +479,10 @@ sub parser_prog {
|
||||||
{
|
{
|
||||||
die "Uncaught exception $1";
|
die "Uncaught exception $1";
|
||||||
}
|
}
|
||||||
|
elsif ($type eq "goto")
|
||||||
|
{
|
||||||
|
die "Target $@->{section} of go statement not found";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
die "$@";
|
die "$@";
|
||||||
}
|
}
|
||||||
|
@ -1191,6 +1195,72 @@ sub macro_dolist {
|
||||||
}
|
}
|
||||||
$macros{dolist} = \¯o_dolist;
|
$macros{dolist} = \¯o_dolist;
|
||||||
|
|
||||||
|
sub macro_tagbody {
|
||||||
|
my $ts = shift;
|
||||||
|
|
||||||
|
my $init_symbol = bless({},"init");
|
||||||
|
|
||||||
|
my $parse_section = $init_symbol;
|
||||||
|
my %schedule;
|
||||||
|
my %sections;
|
||||||
|
$sections{$parse_section} = [];
|
||||||
|
while (!peek_token($ts, RPAREN))
|
||||||
|
{
|
||||||
|
if (peek_token($ts, IDENT))
|
||||||
|
{
|
||||||
|
my $next_parse_section = slurp_token($ts, IDENT)->{value};
|
||||||
|
$schedule{$parse_section} = $next_parse_section;
|
||||||
|
$parse_section = $next_parse_section;
|
||||||
|
$sections{$parse_section} = [];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
push @{$sections{$parse_section}}, parser_expr($ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sub {
|
||||||
|
my $octx = shift;
|
||||||
|
my $ictx = ctx_create($octx);
|
||||||
|
|
||||||
|
my $current_section = $init_symbol;
|
||||||
|
|
||||||
|
do {
|
||||||
|
eval {
|
||||||
|
$_->($ictx) foreach @{$sections{$current_section}};
|
||||||
|
1;
|
||||||
|
};
|
||||||
|
if ($@)
|
||||||
|
{
|
||||||
|
if (ref($@) eq "goto" && exists($sections{$@->{section}}))
|
||||||
|
{
|
||||||
|
$current_section = $@->{section}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
die $@;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$current_section = $schedule{$current_section};
|
||||||
|
}
|
||||||
|
} while($current_section);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
$macros{tagbody} = \¯o_tagbody;
|
||||||
|
|
||||||
|
sub macro_go {
|
||||||
|
my $ts = shift;
|
||||||
|
|
||||||
|
my $ident = slurp_token($ts, IDENT, "Expected identifier after go")->{value};
|
||||||
|
|
||||||
|
return sub {
|
||||||
|
die bless({ section => $ident }, "goto");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
$macros{go} = \¯o_go;
|
||||||
|
|
||||||
sub compile {
|
sub compile {
|
||||||
my ($term) = @_;
|
my ($term) = @_;
|
||||||
my @tokens = tokenize($term);
|
my @tokens = tokenize($term);
|
||||||
|
|
28
t/tagbody.t
Normal file
28
t/tagbody.t
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
(plan 2)
|
||||||
|
|
||||||
|
(defun inc (n) (+ n 1))
|
||||||
|
|
||||||
|
(expect "dotimes - sections are evaluated in order"
|
||||||
|
(equal 'ok
|
||||||
|
(catch 'test
|
||||||
|
(let ((i 0))
|
||||||
|
(tagbody
|
||||||
|
(set i 's0)
|
||||||
|
section-a
|
||||||
|
(unless (equal i 's0) (throw 'test 'fail))
|
||||||
|
(set i 's1)
|
||||||
|
section-b
|
||||||
|
(unless (equal i 's1) (throw 'test 'fail))
|
||||||
|
(set i 's2))
|
||||||
|
(unless (equal i 's2) (throw 'test 'fail)))
|
||||||
|
'ok)))
|
||||||
|
|
||||||
|
(expect "dotimes - go works"
|
||||||
|
(equal 'ok
|
||||||
|
(catch 'test
|
||||||
|
(tagbody
|
||||||
|
(go section-b)
|
||||||
|
section-a
|
||||||
|
(throw 'test 'fail)
|
||||||
|
section-b)
|
||||||
|
'ok)))
|
Loading…
Reference in a new issue