Author: leo
Date: Thu Apr 21 04:07:13 2005
New Revision: 7900
Modified:
trunk/build_tools/pmc2c.pl
trunk/classes/float.pmc
trunk/dynclasses/tclfloat.pmc
trunk/lib/Parrot/Pmc2c.pm
trunk/lib/Parrot/Pmc2c/Library.pm
trunk/src/mmd.c
trunk/t/pmc/mmd.t
Log:
MMD 30 - inheritance of abstract functions
* add MMD variants to pmc dumps
* create MMD_init entries for statically inherited functions
* remove hacks in float.pmc
* fix typo in tclfloat
* better MMD distance sorting
Modified: trunk/build_tools/pmc2c.pl
==============================================================================
--- trunk/build_tools/pmc2c.pl (original)
+++ trunk/build_tools/pmc2c.pl Thu Apr 21 04:07:13 2005
@@ -257,12 +257,12 @@
main();
-#
+#
# my $path = find_file( [$dir1, $dir2], $file, $die_unless_found_flag );
-#
+#
# Return the full path to $file (search in the given directories).
# Optionally, die with an error message if that file cannot be found.
-#
+#
sub find_file {
my ($include, $file, $die_unless_found) = @_;
@@ -277,21 +277,21 @@
undef;
}
-#
+#
# dump_default();
-#
+#
# Create a .dump file for the default vtable (from which all PMCs
# inherit).
-#
+#
sub dump_default {
my $file = "$FindBin::Bin/../vtable.tbl";
my $default = parse_vtable($file);
my $dump = $file;
$dump =~ s/\.\w+$/\.dump/;
-
+
print "Writing $dump\n" if $opt{verbose};
open VTD, ">", $dump or die "Can't write '$dump'";
-
+
my %vtable = (
flags => {},
pre => '',
@@ -311,25 +311,25 @@
};
}
$vtable{'has_method'} = \%meth_hash;
-
+
my $Dumper = Data::Dumper->new([\%vtable], ['class']);
$Dumper->Indent(3);
print VTD $Dumper->Dump();
close VTD;
}
-#
+#
# my ($balanced, $remaining) = extract_balanced($code);
-#
+#
# Remove a balanced {} construct from the beginning of $code.
# Return it and the remaining code.
-#
+#
sub extract_balanced {
my $code = shift;
my $balance = 0;
-
+
$code =~ s/^\s+//;
-
+
# create a copy and remove strings and comments so that
# unbalanced {} can be used in them in PMCs, being careful to
# preserve string length.
@@ -340,9 +340,9 @@
| /\* .*? \*/ ) # remove C comments
]
[ "-" x length $1 ]sexg;
-
+
/^\{/ or die "bad block open: ", substr($code,0,10), "...";
-
+
while (/ (\{) | (\}) /gx) {
if($1) {
$balance++;
@@ -355,20 +355,20 @@
die "Badly balanced" if $balance;
}
-#
+#
# my ($pre, $class_name, $flags) = parse_flags(\$code);
-#
+#
# Extract a class signature from the code ref and return (a) the
# code found before the signature, (b) the name of the class, and
# (c) a hash ref containing the flags associated with the class
# (such as 'extends' and 'does').
-#
+#
sub parse_flags {
my $c = shift;
$$c =~ s/^(.*?^\s*)pmclass ([\w]*)//ms;
my ($pre, $classname) = ($1, $2);
-
+
# flags that have values passed with them
my %has_value = map { $_ => 1 } qw(does extends group lib);
@@ -379,7 +379,7 @@
if ($has_value{$flag}) {
$$c =~ s/^\s+(\w+)//s
or die "Parser error: no value for '$flag'";
-
+
$flags{$flag}{$1} =
$flag eq 'extends' ? ++$parent_nr : 1;
}
@@ -387,22 +387,22 @@
$flags{$flag} = 1;
}
}
-
+
# setup some defaults
if ($classname ne 'default') {
$flags{extends}{default} = 1 unless $flags{extends};
$flags{does}{scalar} = 1 unless $flags{does};
}
-
+
return $pre, $classname, \%flags;
}
-#
+#
# my ($name, $attributes) = parse_pmc($code);
-#
+#
# Parse PMC code and return the class name and a hash ref of
# attributes.
-#
+#
sub parse_pmc {
my $code = shift;
@@ -414,7 +414,7 @@
)*
(METHOD\s+)? #method flag
-
+
(\w+\**) #type
\s+
(\w+) #method name
@@ -424,7 +424,7 @@
my ($pre, $classname, $flags) = parse_flags(\$code);
my ($classblock, $post) = extract_balanced($code);
-
+
my $lineno = 1 + count_newlines($pre);
$classblock = substr($classblock, 1,-1); # trim out the { }
@@ -434,7 +434,7 @@
$lineno += count_newlines($1);
my ($flag, $type, $methodname, $parameters) = ($2,$3,$4,$5);
my ($methodblock, $rema) =
extract_balanced($classblock);
-
+
$methodblock = "" if $opt{nobody};
if ($methodname eq 'class_init') {
$class_init = {
@@ -449,6 +449,7 @@
else {
# name => method idx mapping
$meth_hash{$methodname} = scalar @methods;
+ my @mmds = ($methodblock =~ /MMD_(\w+):/g);
push @methods,
{
meth => $methodname,
@@ -456,13 +457,14 @@
line => $lineno,
type => $type,
parameters => $parameters,
- loc => $flag ? "nci" : "vtable"
+ loc => $flag ? "nci" : "vtable",
+ mmds => [ @mmds ],
};
}
$classblock = $rema;
$lineno += count_newlines($methodblock);
}
-
+
if ($class_init) {
$meth_hash{'class_init'} = scalar @methods;
push @methods, $class_init;
@@ -480,33 +482,33 @@
};
}
-#
+#
# gen_parent_list( [$dir1, $dir2], $class, $classes );
-#
+#
# Generate an ordered list of parent classes to put in the
# $classes->{class}->{parents} array, using the given directories
# to find parents.
-#
+#
sub gen_parent_list {
my ($include, $this, $all) = @_;
my @todo = ($this);
my $class = $all->{$this};
-
+
while (@todo) {
my $n = shift @todo;
my $sub = $all->{$n};
next if $n eq 'default';
-
+
my %parent_hash = %{$sub->{flags}{extends}};
my @parents = sort { $parent_hash{$a} <=> $parent_hash{$b} }
keys %parent_hash;
for my $parent (@parents) {
next if exists $class->{has_parent}{$parent};
-
+
$all->{$parent} = read_dump($include, lc("$parent.pmc"))
if not $all->{$parent};
-
+
$class->{has_parent}{$parent} = { %{$all->{$parent}{has_method} }};
push @todo, $parent;
push @{ $class->{parents} }, $parent;
@@ -515,15 +517,15 @@
}
-#
+#
# my $class = dump_1_pmc($file);
-#
+#
# Generate the class structure from $file for a .dump file.
-#
+#
sub dump_1_pmc {
my $file = shift;
$file =~ s/\.\w+$/.pmc/;
-
+
print "Reading $file\n" if $opt{verbose};
open my $fh, "<", $file
or die "Can't read '$file'";
@@ -531,22 +533,30 @@
return parse_pmc($contents);
}
-#
+#
# gen_super_meths($class, $vtable)
-#
+#
# Generate a list of inherited methods for $class by searching the
# inheritence tree. The method list is found in $vtable.
-#
+#
sub gen_super_meths {
- my ($self, $vt) = @_;
+ my ($self, $vt, $all) = @_;
# look through all meths in class and locate the nearest parent
foreach my $entry (@{ $vt->{methods} } ) {
my $meth = $entry->{meth};
next if exists $self->{super}{$meth};
foreach my $pname (@{ $self->{parents} } ) {
- if (exists $self->{has_parent}{$pname}{$meth} ) {
+ if (exists ($self->{has_parent}{$pname}{$meth} )) {
$self->{super}{$meth} = $pname;
+ my $n = $self->{has_parent}{$pname}{$meth};
+ my $super_mmd = $all->{$pname}{methods}[$n]{mmds};
+ if ($super_mmd && scalar @{ $super_mmd }) {
+ ##print "** @{ $super_mmd } **\n";
+ push @{ $self->{super_mmd} },
+ { $pname => $super_mmd,
+ 'meth' => $meth};
+ }
last;
}
}
@@ -569,13 +579,13 @@
}
}
-#
+#
# add_defaulted($class_structure, $vtable);
-#
+#
# Add methods to the class structure for each method found in the
# vtable. This is used to determine all of the 'default' methods
# from the vtable.dump.
-#
+#
sub add_defaulted {
my ($class, $vt) = @_;
@@ -585,30 +595,30 @@
}
}
-#
+#
# my $newer = dump_is_newer($file);
-#
+#
# Return whether the dump of a file is newer than the PMC file.
# (If it's not, then the PMC file has changed and the dump has
# not been updated.)
-#
+#
sub dump_is_newer {
my $pmc = my $file = shift;
$pmc =~ s/\.\w+$/.pmc/;
-
+
my $pmc_dt = (stat $pmc)[9];
my $dump_dt = (stat $file)[9];
-
+
return $dump_dt > $pmc_dt;
}
-#
+#
# dump_pmc( [$dir1, $dir2], $file1, $file2, ... );
-#
+#
# Create a .dump file for each of the passed files (which can be
# found in the given directories). A '*.pmc' glob may also be passed
# to emulate a proper shell in the presence of a dump one.
-#
+#
sub dump_pmc {
my ($include, @files) = @_;
# help these dumb 'shells' that are no shells
@@ -623,25 +633,25 @@
$all{default} = read_dump($include, "classes/default.pmc")
if not $all{default};
-
+
my $vt = read_dump($include, "vtable.pmc");
add_defaulted($all{default}, $vt);
foreach my $name (keys %all) {
my $file = $all{$name}->{file};
$file =~ s/\.\w+$/\.dump/;
-
+
# XXX write default.dump only once
my $existing = find_file($include, $file);
next if $existing && -e $existing && dump_is_newer($existing);
-
+
my $class = $all{$name};
gen_parent_list($include, $name, \%all);
- gen_super_meths($class, $vt);
-
+ gen_super_meths($class, $vt, \%all);
+
my $Dumper = Data::Dumper->new([$class], ['class']);
$Dumper->Indent(1);
-
+
print "Writing $file\n" if $opt{verbose};
open my $fh, ">", $file or die "Can't write '$file'";
print $fh $Dumper->Dump;
@@ -649,25 +659,25 @@
}
}
-#
+#
# my $class = read_dump( [$dir1, $dir2], $file );
-#
+#
# Read in the class definition found in $file (which is found in one
# of the given directories) and recreate the data structure.
-#
+#
sub read_dump {
my ($include, $file) = @_;
-
+
$file =~ s/\.\w+$/.dump/;
$file = find_file($include, $file, 1);
-
+
print "Reading $file\n" if $opt{verbose};
open my $fh, "<", $file or die "Can't read '$file'";
-
+
my $class;
eval do { local $/; <$fh> };
die $@ if $@;
-
+
close $fh;
$class;
}
@@ -679,45 +689,45 @@
# given directories to search for all of correct PMCs. The middle
# argument is the display depth, which is used for the recursive
# definition of this function.
-#
+#
sub print_tree {
my ($include,$depth, @files) = @_;
for my $file (@files) {
my $class = read_dump($include, $file);
-
+
print " " x $depth, $class->{class}, "\n";
print_tree($include, $depth + 1, lc("$_.pmc"))
for keys %{$class->{flags}{extends}};
}
}
-#
+#
# gen_c( [$dir1, $dir2], $file1, $file2, ... );
-#
+#
# Generate the c source code file for each of the files passed in,
# using the directories passed in to search for the PMC dump files.
-#
+#
sub gen_c {
my ($include, @files) = @_;
my %pmcs = map { $_, read_dump($include, $_) } @files;
-
+
Parrot::Pmc2c::Library
->new( \%opt, read_dump($include, "vtable.pmc"), %pmcs )
->write_all_files;
}
-#
+#
# main()
-#
+#
# Get and set the correct options and execute the runmode
# specified in @ARGS.
-#
+#
sub main {
my ($default, $dump, $gen_c, $tree, @include);
# initialization to prevent warnings
%opt = map { $_ => 0 } qw(nobody nolines debug verbose);
-
+
my $result = GetOptions(
"vtable" => \$default,
"dump" => \$dump,
Modified: trunk/classes/float.pmc
==============================================================================
--- trunk/classes/float.pmc (original)
+++ trunk/classes/float.pmc Thu Apr 21 04:07:13 2005
@@ -20,9 +20,6 @@
#include "parrot/parrot.h"
-PMC* Parrot_scalar_subtract_Complex(Interp* , PMC* pmc, PMC* value, PMC* dest);
-void Parrot_scalar_i_subtract_Complex(Interp* , PMC* pmc, PMC* value);
-
pmclass Float extends scalar {
/*
@@ -209,47 +206,10 @@
*/
void morph (INTVAL type) {
- if (SELF->vtable->base_type == type)
- return;
- if (type == enum_class_String) {
- /*
- * if we morph to a string, first clear str_val
- * so that after changing the vtable a parallel
- * reader doesn't get a garbage pointer
- */
- PMC_str_val(SELF) = NULL;
- PObj_custom_mark_SET(SELF);
- SELF->vtable = Parrot_base_vtables[type];
- return;
- }
- if (type == enum_class_BigInt || type == enum_class_Complex) {
- PMC_str_val(SELF) = NULL;
- SELF->vtable = Parrot_base_vtables[type];
- DYNSELF.init();
- return;
- }
- SELF->vtable = Parrot_base_vtables[type];
+ pmc_reuse(INTERP, SELF, type, 0);
}
- PMC* subtract (PMC* value, PMC* dest) {
-MMD_Complex: {
- return Parrot_scalar_subtract_Complex(interpreter,
- SELF, value, dest); /* XXX inheritance problem */
- }
-MMD_DEFAULT: {
- return SUPER(value, dest); /* XXX inheritance problem */
- }
- }
-
- void i_subtract (PMC* value) {
-MMD_Complex: {
- Parrot_scalar_i_subtract_Complex(interpreter, SELF, value);
- }
-MMD_DEFAULT: {
- SUPER(value); /* XXX inheritance problem */
- }
- }
/*
Modified: trunk/dynclasses/tclfloat.pmc
==============================================================================
--- trunk/dynclasses/tclfloat.pmc (original)
+++ trunk/dynclasses/tclfloat.pmc Thu Apr 21 04:07:13 2005
@@ -23,7 +23,7 @@
-pmclass TclFloat extends TclObject extend Float dynpmc group tcl_group {
+pmclass TclFloat extends TclObject extends Float dynpmc group tcl_group {
void init () {
PMC_num_val(SELF) = 0.0;
Modified: trunk/lib/Parrot/Pmc2c.pm
==============================================================================
--- trunk/lib/Parrot/Pmc2c.pm (original)
+++ trunk/lib/Parrot/Pmc2c.pm Thu Apr 21 04:07:13 2005
@@ -206,19 +206,6 @@
}
$cout .= <<"EOC";
}
-
- /*
- * force rebuilding of the static MMD_table
- * TODO only for classes that have mmds
- */
-EOC
- while (my ($class, $info) = each %classes) {
- next if $info->{flags}->{noinit};
- $cout .= <<"EOC";
- Parrot_mmd_rebuild_table(interpreter, type$class, -1);
-EOC
- }
- $cout .= <<"EOC";
return pmc;
}
@@ -637,8 +624,10 @@
my $sub_meth_name = $1;
my $sub_meth = $sub_meth_decl; # no "static ." ...
$sub_meth =~ s/\(/_$right_type(/;
- $header_decls .= <<EOH;
-$sub_meth;
+ $sub_meth_decl = $sub_meth;
+ $sub_meth_decl =~ s/\n/ /g;
+ $self->{hdecls} .= <<EOH;
+$sub_meth_decl;
EOH
$additional_bodies .= $sub_meth;
$additional_bodies .= "{$body_part\n}";
@@ -647,7 +636,7 @@
}
}
- $cout .= $header_decls;
+ ## $cout .= $header_decls;
$cout .= $self->decl($classname, $method, 0);
# This is the part that comes from the PMC file.
$cout .= $self->line_directive($method->{line}, $self->{file});
@@ -718,6 +707,38 @@
return exists($pmc_types{$_[1]}) ? 0 : 1;
}
+# XXX quick hack - to get MMD variants
+sub get_super_mmds {
+ my ($self, $meth, $right, $func) = @_;
+ ## use Data::Dumper;
+ ## printf "******* $meth_name **********\n";
+ ## print Dumper($self);
+ ## exit 0;
+ my (@mmds, $found);
+ for my $super_mmd (@{ $self->{super_mmd} }) {
+ my ($super, $variants);
+ $found = 0;
+ @mmds = ();
+ while (($super, $variants) = each %{ $super_mmd }) {
+ if ($super eq 'meth' && $variants eq $meth) {
+ $found = 1;
+ }
+ elsif (ref($variants) eq 'ARRAY') {
+ for my $class (@{ $variants }) {
+ next if $class eq 'DEFAULT';
+ my $r = $class eq 'DEFAULT' ? 'enum_type_PMC' :
+ "enum_class_$class";
+ my $super_name = "Parrot_${super}_$meth";
+ $super_name .= "_$class" if $class ne 'DEFAULT';
+ push @mmds, [ $func, 0, $r, $super_name ];
+ }
+ }
+ }
+ last if $found;
+ }
+ return $found ? @mmds : ();
+}
+
=item C<init_func()>
Returns the C code for the PMC's initialization method, or an empty
@@ -780,6 +801,9 @@
$right = 'enum_type_INTVAL' if ($func =~ s/_INT$//);
$right = 'enum_type_FLOATVAL' if ($func =~ s/_FLOAT$//);
$right = 'enum_type_STRING' if ($func =~ s/_STR$//);
+ if (exists $self->{super}{$meth}) {
+ push @mmds, $self->get_super_mmds($meth, $right, $func);
+ }
push @mmds, [ $func, $left, $right, $meth_name ];
foreach my $variant (@{ $self->{mmd_variants}{$meth} }) {
if ($self->pmc_is_dynpmc($variant->[0])) {
@@ -793,6 +817,7 @@
$meth_name = $variant->[1] . '_' .$variant->[0];
push @mmds, [ $func, $left, $right, $meth_name];
}
+ $self->{mmds} = @mmds;
}
}
my $methlist = join(",\n ", @meths);
@@ -1008,7 +1033,8 @@
$hout .= <<"EOC";
void Parrot_${classname}_class_init(Parrot_Interp, int, int);
EOC
- $hout;
+ $self->{hdecls} .= $hout;
+ $self->{hdecls};
}
=item C<gen_h($out_name)>
Modified: trunk/lib/Parrot/Pmc2c/Library.pm
==============================================================================
--- trunk/lib/Parrot/Pmc2c/Library.pm (original)
+++ trunk/lib/Parrot/Pmc2c/Library.pm Thu Apr 21 04:07:13 2005
@@ -58,18 +58,18 @@
local (*H, *C);
print Data::Dumper->Dump([$generator]) if $opt->{debug} > 1;
- my $hout = $generator->gen_h($h_name);
- print $hout if $opt->{debug};
- print "Writing $h_name\n" if $opt->{verbose};
- open H, ">$h_name" or die "Can't write '$h_name";
- print H $hout;
- close H;
my $cout = $generator->gen_c($c_name);
print $cout if $opt->{debug};
print "Writing $c_name\n" if $opt->{verbose};
open C, ">$c_name" or die "Can't write '$c_name";
print C $cout;
close C;
+ my $hout = $generator->gen_h($h_name);
+ print $hout if $opt->{debug};
+ print "Writing $h_name\n" if $opt->{verbose};
+ open H, ">$h_name" or die "Can't write '$h_name";
+ print H $hout;
+ close H;
}
=item C<write_all_files()>
Modified: trunk/src/mmd.c
==============================================================================
--- trunk/src/mmd.c (original)
+++ trunk/src/mmd.c Thu Apr 21 04:07:13 2005
@@ -1252,6 +1252,14 @@
{
short da = (short)a & 0xffff;
short db = (short)b & 0xffff;
+ /* sort first by distance */
+ if (da > db)
+ return 1;
+ if (da < db)
+ return -1;
+ /* end then by index in candidate list */
+ da = a >> 16;
+ db = b >> 16;
return da > db ? 1 : da < db ? -1 : 0;
}
@@ -1385,6 +1393,8 @@
* create a helper structure:
* bits 0..15 = distance
* bits 16..31 = idx in candidate list
+ *
+ * TODO use half of available INTVAL bits
*/
sort = pmc_new(interpreter, enum_class_FixedIntegerArray);
VTABLE_set_integer_native(interpreter, sort, n);
Modified: trunk/t/pmc/mmd.t
==============================================================================
--- trunk/t/pmc/mmd.t (original)
+++ trunk/t/pmc/mmd.t Thu Apr 21 04:07:13 2005
@@ -305,7 +305,6 @@
pir_output_is(<<'CODE', <<'OUT', "first dynamic MMD call");
-.namespace ["Main"]
.sub main @MAIN
.local pmc F, B, f, b, m, s
newclass F, "Foo"
@@ -313,27 +312,25 @@
newclass B, "Bar"
b = B."instantiate"()
# create a multi the hard way
- m = new MultiSub
- s = find_global "Foo", "foo"
- push m, s
- s = find_global "Bar", "foo"
- push m, s
- global "foo" = m
+ ## m = new MultiSub
+ ## s = find_global "Foo", "foo"
+ ## push m, s
+ ## s = find_global "Bar", "foo"
+ ## push m, s
+ ## global "foo" = m
print "calling foo(f, b)\n"
foo(f, b)
print "calling foo(b, f)\n"
foo(b, f)
.end
-.namespace ["Foo"]
-.sub foo method
+.sub foo method, @MULTI(Foo, Bar)
.param pmc x
.param pmc y
print " Foo::foo\n"
.end
-.namespace ["Bar"]
-.sub foo method
+.sub foo method, @MULTI(Bar, Foo)
.param pmc x
.param pmc y
print " Bar::foo\n"
@@ -815,7 +812,6 @@
open P, ">$temp" or die "can't write $temp";
print P <<'EOF';
-.namespace ["__parrot_core"]
.sub __add @MULTI(Integer, Integer)
.param pmc l
.param pmc r