Well, I have Warnock's Dilemma with respect to people with commit
rights for my line numbering patch, but a vote of confidence from Alex
Gough. So here's the PMC inheritance patch (it also includes the line
numbering patch). It supersedes both my previous pmc2c.pl patch and
the followup classes/Makefile.in patch.

Briefly, this allows PMCs to inherit from each other, so that

pmclass CobolInt extends PerlInt {

   FLOATVAL get_number () {
   }

}

will create a cobolint.c with a vtable initializer using
Parrot_CobolInt_get_number() and Parrot_PerlInt_get_integer(). (And if
vtable.tbl contains any ops not appearing in either perlint.pmc or
cobolint.pmc, then they'll be Parrot_default_<method>()). Oh, and

  INTVAL some_method () = default;

is now the same as not declaring some_method() at all. (But it still
notices the declaration, in case someone wants to change it to force
it to use the default implementation even if a superclass overrides
it. But that would be weird.)

This patch does not include documentation, because I suspect jgoff's
PMC.pod, once it materializes, will be a better place for it than
vtable.pod.

Index: classes/pmc2c.pl
===================================================================
RCS file: /home/perlcvs/parrot/classes/pmc2c.pl,v
retrieving revision 1.5
diff -u -r1.5 pmc2c.pl
--- classes/pmc2c.pl    8 Dec 2001 22:07:13 -0000       1.5
+++ classes/pmc2c.pl    4 Jan 2002 02:11:25 -0000
@@ -5,42 +5,130 @@
 # Generate a C source file from the methods defined in a .pmc file.
 #
 
+use FindBin;
+use lib "$FindBin::Bin/..";
+use Parrot::Vtable;
 use strict;
 
+my %default = parse_vtable("$FindBin::Bin/../vtable.tbl");
+my $signature_re = qr{
+    ^
+    (?:             #blank spaces and comments
+      [\n\s]*
+      (?:/\*.*?\*/)?  # C-like comments
+    )*
+  
+    (\w+\**)      #type
+    \s+
+    (\w+)         #method name
+    \s*    
+    \(([^\(]*)\)  #parameters
+}sx;
+
 sub extract_balanced {
     my $balance = 0;
+    my $lines = 0;
     for(shift) {
-        s/^\s+//;
+        s/^(\s+)//;
+        $lines += count_newlines($1);
         /^\{/ or die "bad block open: ".substr($_,0,10),"..."; # }
         while(/(\{)|(\})/g) {
             if($1) {
                 $balance++;
             } else { # $2
-                --$balance or return (substr($_, 0, pos, ""),  $_);
+                --$balance or return (substr($_, 0, pos, ""),  $_, $lines);
             }
         }
         die "Badly balanced" if $balance;
     }
 }
 
+sub parse_superpmc {
+  local $_ = shift;
+
+  my ($classname) = s/(?:.*?)^\s*pmclass ([\w]*)//ms;
+
+  my $superpmc = 'default';
+  my $saw_extends;
+  while (s/^(\s*)(\w+)//s) {
+      if ($saw_extends) {
+          $superpmc = $2;
+          last;
+      } elsif ($2 eq 'extends') {
+          $saw_extends = 1;
+      }
+  }
+
+  my ($classblock) = extract_balanced($_);
+  $classblock = substr($classblock, 1,-1); # trim out the { }
+
+  my @methods;
+
+  while ($classblock =~ s/($signature_re)//) {
+     my $methodname = $3;
+     next if ($classblock =~ s/^(\s*=\s*default;?\s*)//s);
+     push @methods, $methodname;
+     (undef, $classblock) = extract_balanced($classblock);
+  }
+
+  return \@methods, $superpmc;
+}
+
+sub superpmc_info {
+    my $pmc = shift;
+    my $filename = "$FindBin::Bin/\L$pmc\E.pmc";
+    print "Scanning $filename...\n";
+    local $/;
+    open(SUPERPMC, $filename) or die "open superpmc file $filename: $!";
+    my $data = <SUPERPMC>;
+    close SUPERPMC;
+    return parse_superpmc($data);
+}
+
+sub scan_inheritance_tree {
+    my ($class) = @_;
+
+    my %methods; # { methodname => class }
+    while ($class ne 'default') {
+        my ($methods, $super) = superpmc_info($class);
+        foreach my $method (@$methods) {
+            $methods{$method} ||= $class;
+        }
+        $class = $super;
+    }
+
+    foreach my $method (@{ $default{order} }) {
+        $methods{$method} ||= 'default';
+    }
+
+    return \%methods;
+}
+
 sub Usage {
     print STDERR <<_EOF_;
-usage: $0 class.pmc [class2.pmc ...]\n";
+usage: $0 class.pmc [--no-lines] [class2.pmc ...]
+  --no-lines suppresses #line directives
 _EOF_
     exit 1;
 }
 
 #
-# Process command-line argument:
+# Process command-line arguments:
 #
 
-Usage() unless @ARGV;  
+my $suppress_lines;
+Usage() unless @ARGV;
+if ($ARGV[0] eq '--no-lines') {
+    $suppress_lines = 1;
+    shift(@ARGV);
+}
 
 while (my $file = shift @ARGV) {
 
   my $base = $file;
   $base =~ s/\.pmc$//;  
   my $cfile = "$base.c";
+  my $hfile = "$base.h";
 
   die "$0: Could not read class file '$file'!\n" unless -e $file; 
   
@@ -49,87 +137,113 @@
   my $contents = join('', @contents);
   close PMC;
       
-  my $coutput = filter($contents);     # run the filter
+  my ($coutput, $houtput) = filter($contents, $file, $cfile); # run the filter
 
   open (SOURCE, ">$cfile") || die "$0: Could not write file '$cfile'\n";
   print SOURCE $coutput;  
   close SOURCE;
+
+  open (SOURCE, ">$hfile") || die "$0: Could not write file '$hfile'\n";
+  print SOURCE $houtput;
+  close SOURCE;
 }
 
 my %flags;
 
+sub count_newlines {
+    return scalar(() = $_[0] =~ /\n/g);
+}
+
 sub filter {
-  my $contents = shift;
+  my ($contents, $pmcfile, $cfile) = @_;
+  my $lineno = 1;
     
-  $contents =~ s/^([^{]*)pmclass ([\w]*)//s; 
-  my ($pre, $classname) = ($1, $2); 
-
-  $flags{$1}++ while $contents =~ s/^\s*(\w+)//s;
+  $contents =~ s/^(.*?^\s*)pmclass ([\w]*)//ms; 
+  my ($pre, $classname) = ($1, $2);
+  $lineno += count_newlines($1);
+
+  my $methodloc = scan_inheritance_tree($classname);
+
+  my $saw_extends;
+  my $superpmc = 'default';
+  while ($contents =~ s/^(\s*)(\w+)//s) {
+      $lineno += count_newlines($1);
+      if ($saw_extends) {
+          $superpmc = $2;
+          $saw_extends = 0;
+      } elsif ($2 eq 'extends') {
+          $saw_extends = 1;
+      } else {
+          $flags{$2}++;
+      }
+  }
 
-  my ($classblock, $post) = extract_balanced($contents,);
-  $classblock = substr($classblock, 2,-1); # trim out the { }
-
-  my $signature_re = qr{
-    ^
-    (?:             #blank spaces and comments
-      [\n\s]*
-      (?:/\*.*?\*/)?  # C-like comments
-    )*
-  
-    (\w+\**)      #type
-    \s+
-    (\w+)         #method name
-    \s*    
-    \(([^\(]*)\)  #parameters
-  }sx;
-  
+  my ($classblock, $post, $lines) = extract_balanced($contents);
+  $lineno += $lines;
+  $classblock = substr($classblock, 1,-1); # trim out the { }
 
   my @methods;
 
-  my $OUT;
-  my %default;
-
-  while ($classblock =~ s/$signature_re//) {
-     my ($type, $methodname, $parameters) = ($1,$2,$3);
+  my $OUT = '';
+  my $HOUT = '';
+  my %defaulted;
+
+  while ($classblock =~ s/($signature_re)//) {
+     $lineno += count_newlines($1);
+     my ($type, $methodname, $parameters) = ($2,$3,$4);
 
      $parameters = ", $parameters" if $parameters =~ /\w/;
-     if ($classblock =~ s/^\s*= default;?\s*//s) {
-        $default{$methodname}++;
+     if ($classblock =~ s/^(\s*=\s*default;?\s*)//s) {
+        $lineno += count_newlines($1);
+        $defaulted{$methodname}++;
         push @methods, $methodname;
         next;
      }
-     
-     my ($methodblock, $rema) = extract_balanced($classblock);
+
+     my ($methodblock, $rema, $lines) = extract_balanced($classblock);
+     $lineno += $lines;
   
      $methodblock =~ s/SELF/pmc/g;
      $methodblock =~ s/INTERP/interpreter/g;
     
-     $OUT .= "$type Parrot_" . $classname. "_" . "$methodname (struct Parrot_Interp 
*interpreter, PMC* pmc$parameters)";      
+     my $decl = "$type Parrot_${classname}_${methodname} (struct Parrot_Interp 
+*interpreter, PMC* pmc$parameters)";
+     $OUT .= $decl;
+     $HOUT .= "extern $decl;\n";
+     $OUT .= "\n#line $lineno \"$pmcfile\"\n   " unless $suppress_lines;
      $OUT .= $methodblock;
      $OUT .= "\n\n";
 
+     $lineno += count_newlines($methodblock);
      $classblock = $rema;
      push @methods, $methodname;
-     };
+  };
+
+  @methods = map { "Parrot_$methodloc->{$_}_$_" } @{ $default{order} };
 
-  @methods = map {(exists $default{$_} ? "Parrot_default" : 
-                                         "Parrot_$classname") 
-                  ."_$_"} @methods;
   my $methodlist = join (",\n        ", @methods);
   my $initname = "Parrot_$classname" . "_class_init";
- 
-  if (keys %default) {
-      $OUT = "#include \"default.h\"\n\n".$OUT;
+
+  my %visible_supers;
+  @visible_supers{values %$methodloc} = ();
+
+  my $includes = '';
+  foreach my $class (keys %visible_supers) {
+      next if $class eq $classname;
+      $includes .= qq(#include "\L$class.h"\n);
   }
 
   $OUT = <<EOC . $OUT;
+ /* Do not edit - automatically generated from '$pmcfile' by $0 */
 $pre
-
+${includes}
 static STRING* whoami;
 
 EOC
 
-$OUT .= <<EOC unless exists $flags{noinit};
+  unless (exists $flags{noinit}) {
+      my $initline = 1+count_newlines($OUT)+1;
+      $OUT .= qq(#line $initline "$cfile"\n) unless $suppress_lines;
+      $OUT .= <<EOC;
 
 void $initname (void) {
 
@@ -149,8 +263,7 @@
    Parrot_base_vtables[enum_class_$classname] = temp_base_vtable;
 }
 EOC
+  }
 
-  return $OUT;
+  return ($OUT, $HOUT);
 }
-  
-
Index: classes/Makefile.in
===================================================================
RCS file: /home/perlcvs/parrot/classes/Makefile.in,v
retrieving revision 1.11
diff -u -r1.11 Makefile.in
--- classes/Makefile.in 31 Dec 2001 03:06:00 -0000      1.11
+++ classes/Makefile.in 4 Jan 2002 02:13:03 -0000
@@ -21,37 +21,34 @@
 .c$(O):
        $(CC) $(CFLAGS) ${ld_out}$@ -c $<
 
-all : default$(O) perlint$(O) perlnum$(O) perlstring$(O) perlarray$(O) perlundef$(O)
+all : $(O_FILES)
 
-default.c: default.pmc
+default.c default.h: default.pmc
        $(PERL) pmc2c.pl default.pmc
 
 default$(O): $(H_FILES)
 
-default.h: default.c
-       $(PERL) -ne ${PQ}next unless /Parrot_default/; s/{/;/;s/^/extern /;print${PQ} 
default.c > default.h
-
-perlint.c: perlint.pmc 
+perlint.c perlint.h: perlint.pmc 
        $(PERL) pmc2c.pl perlint.pmc
 
 perlint$(O): $(H_FILES)
 
-perlnum.c: perlnum.pmc 
+perlnum.c perlnum.h: perlnum.pmc 
        $(PERL) pmc2c.pl perlnum.pmc
 
 perlnum$(O): $(H_FILES)
 
-perlstring.c: perlstring.pmc 
+perlstring.c perlstring.h: perlstring.pmc 
        $(PERL) pmc2c.pl perlstring.pmc
 
 perlstring$(O): $(H_FILES)
 
-perlarray.c: perlarray.pmc 
+perlarray.c perlarray.h: perlarray.pmc 
        $(PERL) pmc2c.pl perlarray.pmc
 
 perlarray$(O): $(H_FILES)
 
-perlundef.c: perlundef.pmc 
+perlundef.c perlundef.h: perlundef.pmc 
        $(PERL) pmc2c.pl perlundef.pmc
 
 perlundef$(O): $(H_FILES)

Reply via email to