Implement do macro
This commit is contained in:
parent
1ff74f4f6c
commit
7ca4bad9b0
2 changed files with 103 additions and 0 deletions
|
@ -474,6 +474,11 @@ sub slurp_token {
|
||||||
return $tok;
|
return $tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub peek_token {
|
||||||
|
my ($ts, $type) = @_;
|
||||||
|
return $ts->[0]->{type} == $type;
|
||||||
|
}
|
||||||
|
|
||||||
sub parser_list {
|
sub parser_list {
|
||||||
my $ts = shift;
|
my $ts = shift;
|
||||||
|
|
||||||
|
@ -826,6 +831,91 @@ sub macro_or {
|
||||||
}
|
}
|
||||||
$macros{or} = \¯o_or;
|
$macros{or} = \¯o_or;
|
||||||
|
|
||||||
|
sub macro_do {
|
||||||
|
my $ts = shift;
|
||||||
|
|
||||||
|
slurp_token($ts, LPAREN, "Expected ( after do");
|
||||||
|
|
||||||
|
my @vars;
|
||||||
|
|
||||||
|
while(!peek_token($ts, RPAREN))
|
||||||
|
{
|
||||||
|
my $name = undef;
|
||||||
|
my $init = undef;
|
||||||
|
my $step = undef;
|
||||||
|
|
||||||
|
if (peek_token($ts, IDENT))
|
||||||
|
{
|
||||||
|
$name = slurp_token($ts,IDENT)->{value};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slurp_token($ts, LPAREN, "Expected either identifier or ( in var list");
|
||||||
|
|
||||||
|
$name = slurp_token($ts, IDENT)->{value};
|
||||||
|
|
||||||
|
if ( !peek_token($ts, RPAREN) )
|
||||||
|
{
|
||||||
|
$init = parser_expr($ts);
|
||||||
|
|
||||||
|
if ( !peek_token($ts, RPAREN) )
|
||||||
|
{
|
||||||
|
$step = parser_expr($ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slurp_token($ts, RPAREN, "Expected ) after var");
|
||||||
|
}
|
||||||
|
|
||||||
|
push @vars, {
|
||||||
|
name => $name,
|
||||||
|
init => $init,
|
||||||
|
step => $step,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
slurp_token($ts, RPAREN, "Expected ) after var list");
|
||||||
|
|
||||||
|
slurp_token($ts, LPAREN, "Expected ( before end-test-form");
|
||||||
|
|
||||||
|
my $end_test_form = parser_expr($ts);
|
||||||
|
|
||||||
|
my $result_form = macro_progn($ts);
|
||||||
|
|
||||||
|
slurp_token($ts, RPAREN, "Expected ) after resultform");
|
||||||
|
|
||||||
|
my $body = macro_progn($ts);
|
||||||
|
|
||||||
|
return sub {
|
||||||
|
my $octx = shift;
|
||||||
|
my $ictx = ctx_create($octx);
|
||||||
|
|
||||||
|
foreach my $var (@vars)
|
||||||
|
{
|
||||||
|
my $val = undef;
|
||||||
|
$val = $var->{init}->($octx) if defined $var->{init};
|
||||||
|
ctx_set($ictx, $var->{name}, $val);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( !from_lisp_bool($end_test_form->($ictx)) )
|
||||||
|
{
|
||||||
|
$body->($ictx);
|
||||||
|
|
||||||
|
my %steps;
|
||||||
|
foreach my $var (@vars)
|
||||||
|
{
|
||||||
|
next unless defined $var->{step};
|
||||||
|
$steps{$var->{name}} = $var->{step}->($ictx);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx_set($ictx, $_, $steps{$_}) foreach (keys %steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result_form->($ictx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$macros{do} = \¯o_do;
|
||||||
|
|
||||||
sub compile {
|
sub compile {
|
||||||
my ($term) = @_;
|
my ($term) = @_;
|
||||||
my @tokens = tokenize($term);
|
my @tokens = tokenize($term);
|
||||||
|
|
13
t/do.t
Normal file
13
t/do.t
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
(expect "do - simple example"
|
||||||
|
(equal (do ((n 1)) (t n)) 1))
|
||||||
|
|
||||||
|
(defun range (start end)
|
||||||
|
(do ((i (- end 1) (- i 1))
|
||||||
|
(lst (list) (cons i lst)))
|
||||||
|
((< i start) lst)))
|
||||||
|
|
||||||
|
(expect "do - range function"
|
||||||
|
(equal (let ((lst (range 1 4)))
|
||||||
|
(comment lst)
|
||||||
|
lst)
|
||||||
|
(list 1 2 3)))
|
Loading…
Reference in a new issue