I sat down with Dan yesterday and finally got my head around his idea of the multiple forms of some of the vtable methods. Unfortunately, this kinda interrupts what I was doing implementing Perl scalar PMCs. :)
Anyway, instead of having an array of five different ways to add things together, each function taking two PMCs, what we actually want is *true* multimethods: one form which takes a PMC and an INTVAL, a PMC and a BIGINT, a PMC and another PMC, etc. (This means that the implementation of the op add_p_p_i is trivial, for instance.) I also finally now understand the "same as you" type - it means "I am passing you a PMC which is guaranteed to be in the same class as you - you may break the abstraction and directly fiddle with its data pointer." The following patch reworks vtable.h to implement this. It now means that the still going on in classes/ is out of date; genclass.pl will need updating and I need to toss what I've written in the C files. But that's cool, because it allows me to convince myself that we ought to use several different vtables to represent a Perl scalar. (which is *obviously* the Right Way, but once I start doing something my way, it's non-trivial to convince me to change... ;) Here's the patch, anyhow: Index: Makefile.in =================================================================== RCS file: /home/perlcvs/parrot/Makefile.in,v retrieving revision 1.48 diff -d -u -r1.48 Makefile.in --- Makefile.in 2001/11/15 22:29:59 1.48 +++ Makefile.in 2001/11/16 15:29:00 @@ -12,11 +12,14 @@ O_FILES = global_setup$(O) interpreter$(O) parrot$(O) register$(O) \ core_ops$(O) memory$(O) packfile$(O) stacks$(O) string$(O) encoding$(O) \ -chartype$(O) runops_cores$(O) trace$(O) vtable_ops$(O) pmc$(O) classes/intclass$(O) \ +chartype$(O) runops_cores$(O) trace$(O) vtable_ops$(O) pmc$(O) \ encodings/singlebyte$(O) encodings/utf8$(O) encodings/utf16$(O) \ encodings/utf32$(O) chartypes/unicode$(O) chartypes/usascii$(O) resources$(O) \ platform$(O) +# classes/intclass.o and classes/scalarclass.o removed for now, while +# multimethods are being reworked + #DO NOT ADD C COMPILER FLAGS HERE #Add them in Configure.pl--look for the #comment 'ADD C COMPILER FLAGS HERE' @@ -91,7 +94,8 @@ encoding/utf32$(O): $(H_FILES) -classes/intclass$(O): $(H_FILES) +# classes/intclass$(O): $(H_FILES) +# classes/scalarclass$(O): $(H_FILES) interpreter$(O): interpreter.c $(H_FILES) Index: make_vtable_ops.pl =================================================================== RCS file: /home/perlcvs/parrot/make_vtable_ops.pl,v retrieving revision 1.5 diff -d -u -r1.5 make_vtable_ops.pl --- make_vtable_ops.pl 2001/10/28 08:29:59 1.5 +++ make_vtable_ops.pl 2001/11/16 15:29:00 @@ -25,6 +25,7 @@ sub multimethod { my $type = $vtable{$_[0]}{meth_type}; return "" if $type eq "unique"; + return ""; # Spike it for now, until I'm convinced of how to do this return '[$3->vtable->num_type]' if $type eq "num"; return '[$3->vtable->string_type]' if $type eq "str"; die "Coding error - undefined type $type\n"; Index: vtable.tbl =================================================================== RCS file: /home/perlcvs/parrot/vtable.tbl,v retrieving revision 1.7 diff -d -u -r1.7 vtable.tbl --- vtable.tbl 2001/11/15 21:24:43 1.7 +++ vtable.tbl 2001/11/16 15:29:00 @@ -11,6 +11,9 @@ # string void frob INTVAL foo STRING bar # # Note that we don't include the source "PMC* pmc" - that's done implicitly. +# +# "value" in non-unique methods (multimethods) is a magic name. Its type +# will be replaced appropriately. unique INTVAL type unique STRING* name @@ -26,19 +29,19 @@ unique BOOLVAL get_bool unique void* get_value unique BOOLVAL is_same PMC* pmc2 -int void set_integer INTVAL integer -float void set_number FLOATVAL number -str void set_string STRING* string +int void set_integer INTVAL value +float void set_number FLOATVAL value +str void set_string STRING* value unique void set_value void* value -num void add PMC* other PMC* dest -num void subtract PMC* other PMC* dest -num void multiply PMC* other PMC* dest -num void divide PMC* other PMC* dest -num void modulus PMC* other PMC* dest -str void concatenate PMC* other PMC* dest -unique BOOLVAL is_equal PMC* other -unique void logical_or PMC* other PMC* dest -unique void logical_and PMC* other PMC* dest -unique void logical_not PMC* other -str void match PMC* other REGEX* re -str void repeat PMC* other PMC* dest +num void add PMC* value PMC* dest +num void subtract PMC* value PMC* dest +num void multiply PMC* value PMC* dest +num void divide PMC* value PMC* dest +num void modulus PMC* value PMC* dest +str void concatenate PMC* value PMC* dest +unique BOOLVAL is_equal PMC* value +unique void logical_or PMC* value PMC* dest +unique void logical_and PMC* value PMC* dest +unique void logical_not PMC* value +str void match PMC* value REGEX* re +str void repeat PMC* value PMC* dest Index: Parrot/Vtable.pm =================================================================== RCS file: /home/perlcvs/parrot/Parrot/Vtable.pm,v retrieving revision 1.7 diff -d -u -r1.7 Vtable.pm --- Parrot/Vtable.pm 2001/10/28 08:29:59 1.7 +++ Parrot/Vtable.pm 2001/11/16 15:29:00 @@ -4,12 +4,22 @@ @Parrot::Vtable::ISA = qw(Exporter); @Parrot::Vtable::EXPORT = qw(parse_vtable vtbl_defs vtbl_struct vtbl_enumerate); -my(%type_counts) = (unique => 1, - int => 5, - float =>5, - num =>7, - str => 5); +my(%expand) = ( + unique => [""], # Dummy element, so we go through the loop exactly once + int => [qw[object native bigint same]], + float => [qw[object native bigfloat same]], + num => [qw[object int bigint float bigfloat same]], + str => [qw[object native unicode other same]] +); + +my (%types) = ( + int => ["PMC *", "INTVAL", "BIGINT", "PMC *"], + float => ["PMC *", "FLOATVAL", "BIGFLOAT", "PMC *"], + num => ["PMC *", "INTVAL", "BIGINT", "FLOATVAL", "BIGFLOAT", "PMC *"], + str => ["PMC *", "STRING *", "STRING *", "STRING *", "PMC *"] +); + sub parse_vtable { my (%vtbl, @order); open IN, shift || "vtable.tbl" or die "Can't open vtable table! $!\n"; @@ -22,38 +32,44 @@ my $meth_type = shift @line; # Method type my $tn = shift @line; # Type and name; my ($type, $name) = $tn =~ /(.*?)\s+(\w+)/; - $vtbl{$name}{type} = $type; - $vtbl{$name}{meth_type} = $meth_type; - $vtbl{$name}{proto} = "$type (*$name)(struct Parrot_Interp *interpreter, PMC* pmc"; - for (@line) { - my ($argtype, $argname) = /(.*?)\s+(\w+)/; - push @{$vtbl{$name}{args}}, - { type => $argtype, name => $argname }; - $vtbl{$name}{proto} .= ", $_"; + + # You are in a maze of twisty multimethods, all different. + for my $i (0..$#{$expand{$meth_type}}) { + my $expand_name = $name; + + # If we're in a multimethod, we need to expand the name if + # it's not the default argument type of "object". + $expand_name .= "_".$expand{$meth_type}[$i] + unless $meth_type eq "unique" + or $expand{$meth_type}[$i] eq "object"; # as a default + + $vtbl{$expand_name}{type} = $type; + $vtbl{$expand_name}{proto} = "$type (*$expand_name)(struct Parrot_Interp +*interpreter, PMC* pmc"; + + # Parse the function parameters + for (@line) { + my ($argtype, $argname) = /(.*?)\s+(\w+)$/; + + # In multimethods, we need to rewrite the type of + # parameters called "value". + $argtype = $types{$meth_type}[$i] + if $argname eq "value" and $meth_type ne "unique"; + + # Add the function parameters to the prototype + push @{$vtbl{$expand_name}{args}}, + { type => $argtype, name => $argname }; + $vtbl{$expand_name}{proto} .= ", $argtype $argname"; + } + $vtbl{$expand_name}{proto} .=")"; + + # So they're ordered according to their position in the file + push @order, $expand_name; } - $vtbl{$name}{proto} .=")"; - push @order, $name; } $vtbl{order} = [@order]; return %vtbl; } -# This code is unused, but I'm keeping it around in case -# we ever go back to using array-based vtables. -sub vtbl_defs { - my %vtbl = @_; - my $rv; - my $offset = 0; - - # First, typedef all the methods. - for (@{$vtbl{order}}) { - my $decl = "VTABLE_" . uc($_); - $rv .= "#define $decl $offset\n"; - $offset += $type_counts{$vtbl{$_}{meth_type}}; - } - return $rv; -} - sub vtbl_struct { my %vtbl = @_; my $rv; @@ -85,14 +101,14 @@ return $rv; } -# Returns an array of [type, name, prototype, variations] arrays +# Returns an array of [type, name, prototype] arrays sub vtbl_enumerate { my %vtbl = @_; my @rv; for (@{$vtbl{order}}) { my $proto = $vtbl{$_}{proto}; $proto =~ s/\(\*$_\)/$_ /; - push @rv, [ "${_}_method_t", $_, $proto, $type_counts{$vtbl{$_}{meth_type}}]; + push @rv, [ "${_}_method_t", $_, $proto]; } return @rv; } Index: include/parrot/parrot.h =================================================================== RCS file: /home/perlcvs/parrot/include/parrot/parrot.h,v retrieving revision 1.12 diff -d -u -r1.12 parrot.h --- include/parrot/parrot.h 2001/11/02 12:11:16 1.12 +++ include/parrot/parrot.h 2001/11/16 15:29:00 @@ -64,6 +64,8 @@ typedef unsigned char BOOLVAL; typedef void STRING_FUNCS; typedef void REGEX; +typedef void BIGINT; +typedef void BIGFLOAT; #include "parrot/global_setup.h" #include "parrot/interpreter.h" -- >Almost any animal is capable learning a stimulus/response association, >given enough repetition. Experimental observation suggests that this isn't true if double-clicking is involved. - Lionel, Malcolm Ray, asr.