# New Ticket Created by  Jürgen Bömmels 
# Please include the string:  [perl #23547]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=23547 >


Hello,

I don't want to let my scheme playground to diverge to far from CVS,
so here is an intermediate patch.

It implements quasiquote and changes write to use Continuation Passing
Style. Some tests for quasiquote were added.

There is also a start of implementing the apply function in
continuation passing style, but its completely untested by now.

bye
boe



-- attachment  1 ------------------------------------------------------
url: http://rt.perl.org/rt2/attach/63534/46631/5a6663/scheme3.diff

Index: languages/scheme/Scheme.pm
===================================================================
RCS file: /cvs/public/parrot/languages/scheme/Scheme.pm,v
retrieving revision 1.2
diff -u -r1.2 Scheme.pm
--- languages/scheme/Scheme.pm	2 Aug 2003 23:05:19 -0000	1.2
+++ languages/scheme/Scheme.pm	20 Aug 2003 23:42:50 -0000
@@ -23,10 +23,16 @@
 
   my $code = $main->{code};
 
+  my $header = "# Header information\n        new_pad 0\n";
+
   while (@missing) {
     my $miss = shift @missing;
 
     my $link = Scheme::Builtins->generate($miss);
+    $header .= << "END";
+        newsub P16, .Sub, ${miss}_ENTRY
+        store_lex 0, "$miss", P16
+END
 
     push @function, $miss;
 
@@ -39,7 +45,7 @@
     $code .= $link->{code};
   }
 
-  $code;
+  $header . $code;
 }
 
 sub compile {
Index: languages/scheme/Scheme/Builtins.pm
===================================================================
RCS file: /cvs/public/parrot/languages/scheme/Scheme/Builtins.pm,v
retrieving revision 1.3
diff -u -r1.3 Builtins.pm
--- languages/scheme/Scheme/Builtins.pm	2 Aug 2003 23:05:22 -0000	1.3
+++ languages/scheme/Scheme/Builtins.pm	20 Aug 2003 23:42:50 -0000
@@ -23,7 +23,9 @@
   ['write_NEXT',   'set', 'P6', 'P5'],
   ['',             'set', 'P5', 'P6[0]'],
   ['',             'save', 'P6'],
-  ['',             'bsr', 'write_ENTRY'],
+  ['',             'save', 'P1'],
+  ['',             'invokecc'],
+  ['',             'restore', 'P1'],
   ['',             'restore', 'P6'],
   ['',             'set', 'P5', 'P6[1]'],
   ['',             'typeof', 'I0', 'P5'],
@@ -32,9 +34,72 @@
   ['',             'print', '" "'],
   ['',             'branch', 'write_NEXT'],
   ['write_DOT',    'print', '" . "'],
-  ['',             'bsr', 'write_ENTRY'],
+  ['',             'save', 'P1'],
+  ['',             'invokecc'],
+  ['',             'restore', 'P1'],
   ['write_KET',    'print', '")"'],
-  ['write_RET',    'ret'],
+  ['write_RET',    'invoke', 'P1'],
+ ],
+ apply => 
+ [['# Apply function'],
+  ['apply_ENTRY', 'set', 'P0', 'P5'],
+  ['',            'set', 'P16', 'P6'],
+  ['',            'typeof', 'I16', 'P16'],
+  ['',            'set', 'I1', 0],
+  ['',            'set', 'I2', 0],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P5', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P6', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P7', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P8', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P9', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P10', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P11', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P12', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P13', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P14', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P15', 'P16[0]'],
+  ['',            'bsr', 'apply_HELP'],
+  ['',            'eq', 'I16', '.PerlUndef', 'apply_CALL'],
+  ['',            'set', 'P17', 'P16'],
+  ['apply_COUNT', 'ne', 'I16', '.PerlUndef', 'apply_ARRAY'],
+  ['',            'inc', 'I2'],
+  ['',            'set', 'P17', 'P17[1]'],
+  ['',            'typeof', 'I16', 'P17'],
+  ['',            'branch', 'apply_COUNT'],
+  ['apply_ARRAY', 'new', 'P3', '.Array'],
+  ['',            'set', 'P3', 'I2'],
+  ['',            'set', 'I16', 0],
+  ['apply_ITER',  'set', 'P3[I16]', 'P16[0]'],
+  ['',            'set', 'P16', 'P16[1]'],
+  ['',            'inc', 'I16'],
+  ['',            'ne', 'I16', 'I2', 'apply_ITER'],
+  ['apply_CALL',  'set', 'I0', 0],
+  ['',            'invoke'],
+  ['apply_HELP',  'P16', 'P16[1]'],
+  ['',            'inc', 'I1'],
+  ['',            'typeof', 'I16', 'P16'],
+  ['',            'ret'],
  ],
 );
 
Index: languages/scheme/Scheme/Generator.pm
===================================================================
RCS file: /cvs/public/parrot/languages/scheme/Scheme/Generator.pm,v
retrieving revision 1.5
diff -u -r1.5 Generator.pm
--- languages/scheme/Scheme/Generator.pm	2 Aug 2003 23:05:22 -0000	1.5
+++ languages/scheme/Scheme/Generator.pm	20 Aug 2003 23:42:51 -0000
@@ -124,6 +124,7 @@
   my ($self, $symbol) = @_;
   my $return = $self->_save_1 ('P');
   $self->_add_inst ('','find_lex',[$return,"\"$symbol\""]);
+
   return $return;
 }
 
@@ -135,6 +136,17 @@
 sub _new_lex {
   my ($self, $symbol, $value) = @_;
   $self->_add_inst ('','store_lex',[-1,"\"$symbol\"",$value]);
+  $self->{scope}->{$symbol} = $value;
+}
+
+sub _new_pair {
+  my ($self) = @_;
+  my $return = $self->_save_1('P');
+
+  $self->_add_inst('', 'new', [$return,'.Array']);
+  $self->_add_inst('', 'set', [$return, 2]);
+
+  return $return;
 }
 
 #------------------------------------
@@ -188,8 +200,7 @@
 #---- Section 4 ----
 
 sub __quoted {
-  my ($self, $node) = @_;
-  my $return = $self->_save_1 ('P');
+  my ($self, $node, $return, $special) = @_;
 
   if (exists $node->{value}) {
     my $value = $node->{value};
@@ -207,13 +218,27 @@
     }
   }
   elsif (exists $node->{children}) {
+    my $children = $node->{children};
+ 
     $self->_add_inst ('', 'new', [$return,'.PerlUndef']);
-    for (reverse @{$node->{children}}) {
+    for (reverse @$children) {
+      if (exists $_->{children}) {
+        my $arg0 = _get_arg($_, 0);
+        if (exists $arg0->{value}) {
+          my $value = $arg0->{value};
+          if (exists $special->{$value}) {
+            _num_arg($_, 1);
+            $special->{$value}->($self, _get_arg($_, 1), $return);
+            next;
+          }
+        }
+      }
+      my $item = $self->_save_1 ('P');
+
+      __quoted ($self, $_, $item, $special);
+
+      my $pair = $self->_new_pair();
 
-      my $item = __quoted ($self, $_);
-      my $pair = $self->_save_1 ('P');
-      $self->_add_inst ('', 'new', [$pair,'.Array']);
-      $self->_add_inst ('', 'set', [$pair,2]);
       $self->_add_inst ('', 'set', [$pair.'[0]',$item]);
       $self->_add_inst ('', 'set', [$pair.'[1]',$return]);
       $self->_add_inst ('', 'set', [$return,$pair]);
@@ -226,13 +251,94 @@
 
 sub _op_quote {
   my ($self, $node) = @_;
-  my $return;
+  my $return = $self->_save_1 ('P');
 
   _num_arg ($node, 1, 'quote');
 
   my $item = _get_arg($node,1);
 
-  return __quoted ($self, $item);
+  return __quoted ($self, $item, $return, {});
+}
+
+sub _op_quasiquote {
+  my ($self, $node) = @_;
+  my $return = $self->_save_1 ('P');
+  my $special = { 
+		  unquote => \&_qq_unquote,
+		  'unquote-splicing' => \&_qq_unquote_splicing
+		};
+
+  _num_arg ($node, 1, 'quote');
+
+  my $item = _get_arg($node,1);
+
+  __quoted ($self, $item, $return, $special);
+}
+
+# helper functions for quasiquote
+
+sub _qq_unquote {
+  my ($self, $node, $return) = @_;
+
+  my $item = $self->_generate($node);
+
+  if ($item =~ /^[INS]/) {
+    my $temp = $self->_save_1('P');
+    $self->_morph($temp, $item);
+    $self->_restore($item);
+    $item = $temp;
+  }
+  my $pair = $self->_new_pair;
+  $self->_add_inst('', 'set', [$pair.'[0]',$item]);
+  $self->_add_inst('', 'set', [$pair.'[1]',$return]);
+  $self->_add_inst('', 'set', [$return,$pair]);
+  $self->_restore($item, $pair);
+
+  return $return;
+}
+
+sub _qq_unquote_splicing {
+  my ($self, $node, $return) = @_;
+
+  my $list = $self->_generate($node);
+
+  die "unquote-splicing called on no list" if ($list =~ /^[INS]/);
+
+  my $type = $self->_save_1('I');
+  my $head = $self->_save_1('P');
+  my $label = $self->_gensym;
+
+  # check for empty list
+  $self->_add_inst('', 'typeof', [$type, $list]);
+  $self->_add_inst('', 'eq', [$type,'.PerlUndef',"DONE_$label"]);
+
+  my $copy = $self->_new_pair;
+
+  $self->_add_inst('', 'set', [$head, $copy]);
+
+  # maybe ensure that $type is a pair here
+  my $temp = $self->_save_1('P');
+  $self->_add_inst("ITER_$label", 'set', [$temp,$list.'[0]']);
+  $self->_add_inst('', 'set', [$copy.'[0]',$temp]);
+  $self->_restore($temp);
+
+  $self->_add_inst('', 'set', [$list,$list.'[1]']);
+  $self->_add_inst('', 'typeof', [$type,$list]);
+  $self->_add_inst('', 'eq', [$type,'.PerlUndef',"FINISH_$label"]);
+
+  $temp = $self->_new_pair;
+  $self->_add_inst('', 'set', [$copy.'[1]',$temp]);
+  $self->_add_inst('', 'set', [$copy,$temp]);
+  $self->_add_inst('', 'branch', ["ITER_$label"]);
+  $self->_restore($temp);
+
+  # append the rest to the end of list
+  $self->_add_inst("FINISH_$label", 'set', [$copy.'[1]',$return]);
+  $self->_add_inst('', 'set', [$return,$head]);
+  $self->_add_inst("DONE_$label");
+
+  $self->_restore($list, $copy, $head, $type);
+  return $return;
 }
 
 sub _op_lambda {
@@ -243,12 +349,7 @@
 
   $return = $self->_save_1 ('P');
 
-  $self->_add_inst ('', 'new',[$return,'.Closure']);
-
-  my $addr = $self->_save_1 ('I');
-  $self->_add_inst ('', 'set_addr',[$addr,"LAMBDA_$label"]);
-  $self->_add_inst ('', 'set',[$return,$addr]);
-  $self->_restore ($addr);
+  $self->_add_inst ('', 'newsub',[$return,'.Closure',"LAMBDA_$label"]);
 
   $self->_add_inst ('', 'branch',["DONE_$label"]);
   $self->_add_inst ("LAMBDA_$label");
@@ -258,9 +359,12 @@
   $self->{regs} = _new_regs;
   # P1 is the return contination
   $self->{regs}{P}{1} = 1;
-
+  
   # expand the lexical scope
   $self->_add_inst('', 'new_pad', [-1]);
+  my $oldscope = $self->{scope};
+  $self->{scope} = { '*UP*' => $oldscope };
+
   my $num = 5;
   my @args = @{_get_arg($node,1)->{children}};
   for (@args) {
@@ -282,6 +386,7 @@
   $self->_add_inst("DONE_$label");
 
   $self->{regs} = pop @{$self->{frames}};
+  $self->{scope} = $self->{scope}->{'*UP*'};
 
   return $return;
 }
@@ -315,25 +420,29 @@
 
   _num_arg ($node, 2, 'define');
 
-  my ($symbol, $value);
+  my ($symbol, $lambda, $value);
 
   if (exists _get_arg($node,1)->{children}) {
     my @formals;
     ($symbol, @formals) = @{_get_arg($node,1)->{children}};
     $symbol = $symbol->{value};
-    my $lambda = { children => [ { value => 'lambda' },
-				 { children => [ @formals ] },
-				 _get_args ($node, 2) ] };
-    $value = $self->_generate($lambda);
+    $lambda = { children => [ { value => 'lambda' },
+                              { children => [ @formals ] },
+                              _get_args ($node, 2) ] };
   }
   else {
     $symbol = _get_arg($node,1)->{value};
-    $value = $self->_generate (_get_arg($node,2));
+    $lambda = _get_arg($node,2);
   }
 
   if (exists $self->{scope}->{$symbol}) {
     die "define: $symbol is already defined\n";
   }
+  else {
+    $self->{scope}->{$symbol} = '*unknown*';
+  }
+
+  $value = $self->_generate($lambda);
 
   if ($value !~ /^P/) {
     my $pmc = $self->_save_1 ('P');
@@ -342,7 +451,6 @@
     $value = $pmc;
   }
 
-  $self->{scope}->{$symbol} = 1;
   $self->_new_lex ($symbol,$value);
 
   return $value;
@@ -478,9 +586,6 @@
 sub _op_delay {
 }
 
-sub _op_quasiquote {
-}
-
 #---- Section 6 ----
 
 sub _op_not {
@@ -1360,17 +1465,7 @@
   my @args = _get_args ($node, 2);
   die "apply: wrong number of args\n" unless @args;
 
-  my $argl = $self->_generate(pop @args);
-  while (@args) {
-    my $elem = $self->_generate(pop @args);
-    my $pair = _save_1('P');
-    $self->_add_inst ('','new',[$pair,'.Array']);
-    $self->_add_inst ('','set',[$pair,2]);
-    $self->_add_inst ('','set',[$pair.'[0]',$elem]);
-    $self->_add_inst ('','set',[$pair.'[1]',$argl]);
-  }
-
-#  $return = $self->_call_function ('apply');
+  $return = $self->_call_function_sym('apply');
 
   return $return;
 }
@@ -1448,13 +1543,8 @@
     if ($temp =~ /[INS]/) {
       $self->_add_inst('','print',[$temp]);
     }
-    else {
-      push @{$self->{functions}}, 'write'
-	unless grep { $_ eq 'write' } @{$self->{functions}};
-      $self->_save_set;
-      $self->_add_inst('', 'set', ['P5', $temp]);
-      $self->_add_inst('', 'bsr', ['write_ENTRY']);
-      $self->_restore_set;
+    else {  
+      $self->_call_function_sym('write',$temp);
     }
   }
   return $temp; # We need to return something
@@ -1815,7 +1905,28 @@
   @max_len;
 }
 
-sub _call_function {
+sub _call_function_sym {
+  my $self = shift;
+  my $symbol = shift;
+  my $func_obj = $self->_find_lex($symbol);
+
+  my $scope = $self->{scope};
+
+  while ($scope && !exists $scope->{$symbol}) {
+    $scope = $scope->{'*UP*'};
+  }
+  if (!$scope) {
+    push @{$self->{functions}}, $symbol
+      unless grep { $_ eq $symbol} @{$self->{functions}};
+  }
+
+  my $return = $self->_call_function_obj($func_obj, @_);
+  $self->_restore($func_obj);
+
+  return $return;
+}
+
+sub _call_function_obj {
   my $self = shift;
   my $func_obj = shift;
 
@@ -1890,6 +2001,7 @@
     frames => [],
     gensym   => 0,
     functions=> [],
+    scope    => {},
   };
   bless $self,$class;
 }
@@ -1918,14 +2030,13 @@
       if (exists $global_ops{$symbol}) {
 	$return = $global_ops{$symbol}->($self, $node);
       } else {
-	my $func_obj = $self->_find_lex ($symbol);
 	my @args = map { $self->_generate($_); } _get_args($node);
-	$return = $self->_call_function($func_obj, @args);
-	$self->_restore($func_obj, @args);
+	$return = $self->_call_function_sym($symbol, @args);
+	$self->_restore(@args);
       }
     } else {
       my @args = map { $self->_generate($_); } _get_args($node, 0);
-      $return = $self->_call_function(@args);
+      $return = $self->_call_function_obj(@args);
       $self->_restore(@args);
     }
   } else {
@@ -1946,11 +2057,9 @@
   my $temp;
 
   $self->{scope} = {};
-  $self->_add_inst ('', 'new_pad',[0]);
 
   $temp = $self->_generate($tree);
 
-  $self->_add_inst ('', 'pop_pad');
   $self->_restore($temp);
   $self->_add_inst('',"end");
 
Index: languages/scheme/Scheme/Parser.pm
===================================================================
RCS file: /cvs/public/parrot/languages/scheme/Scheme/Parser.pm,v
retrieving revision 1.3
diff -u -r1.3 Parser.pm
--- languages/scheme/Scheme/Parser.pm	12 Dec 2002 16:01:29 -0000	1.3
+++ languages/scheme/Scheme/Parser.pm	20 Aug 2003 23:42:52 -0000
@@ -33,6 +33,27 @@
     ($count, $expr) = _build_tree ($tokens, $count);
     push @{$temp->{children}}, $expr;
   }
+  elsif ($tokens->[$count] eq "`") {
+    $temp = { children => [{ value => 'quasiquote' }] };
+    my $expr;
+    $count++;
+    ($count, $expr) = _build_tree ($tokens, $count);
+    push @{$temp->{children}}, $expr;
+  }
+  elsif ($tokens->[$count] eq ",") {
+    $temp = { children => [{ value => 'unquote' }] };
+    my $expr;
+    $count++;
+    ($count, $expr) = _build_tree ($tokens, $count);
+    push @{$temp->{children}}, $expr;
+  }
+  elsif ($tokens->[$count] eq ",@") {
+    $temp = { children => [{ value => 'unquote-splicing' }] };
+    my $expr;
+    $count++;
+    ($count, $expr) = _build_tree ($tokens, $count);
+    push @{$temp->{children}}, $expr;
+  }
   else {
     $temp->{value} = $tokens->[$count++];
   }
Index: languages/scheme/Scheme/Tokenizer.pm
===================================================================
RCS file: /cvs/public/parrot/languages/scheme/Scheme/Tokenizer.pm,v
retrieving revision 1.4
diff -u -r1.4 Tokenizer.pm
--- languages/scheme/Scheme/Tokenizer.pm	12 Dec 2002 16:01:29 -0000	1.4
+++ languages/scheme/Scheme/Tokenizer.pm	20 Aug 2003 23:42:52 -0000
@@ -55,6 +55,9 @@
     } elsif($ch =~ /\s/ and
             $token =~ /^\s/) {    # White can follow white
       $token .= $ch;
+    } elsif($ch =~ /@/ and
+	    $token =~ /^,$/) {    # token ,@
+      $token .= $ch;
     } else {
       push @$tokref,$token;
       $token = $ch;
Index: languages/scheme/t/logic/lists.t
===================================================================
RCS file: /cvs/public/parrot/languages/scheme/t/logic/lists.t,v
retrieving revision 1.2
diff -u -r1.2 lists.t
--- languages/scheme/t/logic/lists.t	12 Dec 2002 16:01:31 -0000	1.2
+++ languages/scheme/t/logic/lists.t	20 Aug 2003 23:42:52 -0000
@@ -1,6 +1,6 @@
 #! perl -w
 
-use Scheme::Test tests => 21;
+use Scheme::Test tests => 26;
 
 output_is(<<'CODE', '(2 . 5)', 'cons');
 (write (cons 2 5))
@@ -105,4 +105,29 @@
 output_is (<<'CODE', '(1 2 (3 4))', 'complex list II');
 (write
   (list 1 2 (list 3 4)))
+CODE
+
+output_is (<<'CODE', '(list 3 4)', 'quasiquote');
+(write
+  `(list ,(+ 1 2) 4))
+CODE
+
+output_is (<<'CODE', '(quasiquote (list (unquote (+ 1 2)) 4))', 'quoted quasiquote');
+(write
+  '`(list ,(+ 1 2) 4))
+CODE
+
+output_is(<<'CODE', '(list 1 2 3)', 'unquote-splicing');
+(write
+  `(list ,@(list 1 2 3)))
+CODE
+
+output_is(<<'CODE', '(list)', 'splicing empty list');
+(write
+  `(list ,@(list)))
+CODE
+
+output_is(<<'CODE', '(list 1 2 3 (4 5))', 'complex quasiquote');
+(write
+  `(list ,@(list 1 2) ,(+ 1 2) ,(list 4 5)))
 CODE

Reply via email to