Skip to content

Commit ed37a36

Browse files
committed
Apply patch from Richard Hainsworth to add Parrot vtable delegation.
1 parent a555ce0 commit ed37a36

File tree

7 files changed

+209
-3
lines changed

7 files changed

+209
-3
lines changed

src/6model/sixmodelobject.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ typedef struct {
1414
PMC *sc; /* Serialization context. */
1515
} SixModelObjectCommonalities;
1616

17+
typedef struct {
18+
PMC *class_handle; /* Class handle */
19+
STRING *att_name; /* Name of the attribute. */
20+
} ParrotVtableHandlerSlot;
21+
1722
/* S-Tables (short for Shared Table) contains the commonalities shared between
1823
* a (HOW, REPR) pairing (for example, (HOW for the class Dog, P6Opaque). */
1924
typedef struct {
@@ -61,6 +66,11 @@ typedef struct {
6166
/* Parrot-specific set of v-table to method mappings, for overriding
6267
* of Parrot v-table functions. */
6368
PMC **parrot_vtable_mapping;
69+
70+
/**
71+
* Parrot-specific set of v-table to object method mappings */
72+
ParrotVtableHandlerSlot *parrot_vtable_handler_mapping;
73+
6474
} STable;
6575

6676
/* A representation is what controls the layout of an object and storage of

src/NQP/Actions.pm

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,14 @@ class NQP::Actions is HLL::Actions {
661661
));
662662
$BLOCK.symbol($name, :scope('lexical') );
663663
}
664+
665+
# Apply traits.
664666
make $past;
667+
668+
if $<trait> {
669+
for $<trait> { $_.ast()($/); }
670+
}
671+
665672
}
666673

667674
method routine_declarator:sym<sub>($/) { make $<routine_def>.ast; }
@@ -983,6 +990,17 @@ class NQP::Actions is HLL::Actions {
983990
$match.ast<block_past>, $is_dispatcher);
984991
};
985992
}
993+
elsif $<longname> eq 'parrot_vtable_handler' {
994+
# XXX This should be in Parrot-specific module and need a pragma.
995+
my $cpast := $<circumfix>[0].ast;
996+
$/.CURSOR.panic("Trait 'parrot_vtable_handler' requires constant scalar argument")
997+
unless $cpast ~~ PAST::Val;
998+
my $name := $cpast.value;
999+
my $package := $*PACKAGE;
1000+
make -> $match {
1001+
$*SC.pkg_add_parrot_vtable_handler_mapping($package, $name, ~$match<variable>);
1002+
};
1003+
}
9861004
elsif $<longname> eq 'pirflags' {
9871005
$/.CURSOR.panic("Trait 'pirflags' no longer supported; use 'is vtable'");
9881006
}

src/NQP/Grammar.pm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ grammar NQP::Grammar is HLL::Grammar {
404404
:my $*IN_DECL := 'variable';
405405
<variable>
406406
{ $*IN_DECL := 0; }
407+
<trait>*
407408
}
408409

409410
proto token routine_declarator { <...> }

src/NQP/SymbolTable.pm

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,21 @@ class NQP::SymbolTable is HLL::Compiler::SerializationContextBuilder {
363363
self.get_object_sc_ref_past($to_add)
364364
)));
365365
}
366-
366+
367+
method pkg_add_parrot_vtable_handler_mapping($obj, $name, $att_name) {
368+
# Do the actual addition on the meta-object immediately.
369+
$obj.HOW.add_parrot_vtable_handler_mapping($obj, $name, $att_name);
370+
371+
# Emit code to add it when deserializing.
372+
my $slot_past := self.get_slot_past_for_object($obj);
373+
self.add_event(:deserialize_past(PAST::Op.new(
374+
:pasttype('callmethod'), :name('add_parrot_vtable_handler_mapping'),
375+
PAST::Op.new( :pirop('get_how PP'), $slot_past ),
376+
$slot_past,
377+
$name, $att_name
378+
)));
379+
}
380+
367381
# Composes the package, and stores an event for this action.
368382
method pkg_compose($obj) {
369383
# Compose.

src/how/NQPClassHOW.pm

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ knowhow NQPClassHOW {
3333

3434
# Parrot-specific vtable mapping hash. Maps vtable name to method.
3535
has %!parrot_vtable_mapping;
36-
36+
has %!parrot_vtable_handler_mapping;
3737
##
3838
## Declarative.
3939
##
@@ -126,6 +126,15 @@ knowhow NQPClassHOW {
126126
%!parrot_vtable_mapping{$name} := $meth;
127127
}
128128

129+
method add_parrot_vtable_handler_mapping($obj, $name, $att_name) {
130+
if pir::defined(%!parrot_vtable_handler_mapping{$name}) {
131+
pir::die("Class '" ~ $!name ~
132+
"' already has a Parrot v-table handler for '" ~
133+
$name ~ "'");
134+
}
135+
%!parrot_vtable_handler_mapping{$name} := [ $obj, $att_name ];
136+
}
137+
129138
method compose($obj) {
130139
# Incorporate roles. First, instantiate them with the type object
131140
# for this type (so their $?CLASS is correct). Then delegate to
@@ -166,6 +175,7 @@ knowhow NQPClassHOW {
166175

167176
# Install Parrot v-table mapping.
168177
self.publish_parrot_vtable_mapping($obj);
178+
self.publish_parrot_vtablee_handler_mapping($obj);
169179

170180
$obj
171181
}
@@ -354,6 +364,20 @@ knowhow NQPClassHOW {
354364
}
355365
}
356366

367+
method publish_parrot_vtablee_handler_mapping($obj) {
368+
my %mapping;
369+
for @!mro {
370+
my %map := $_.HOW.parrot_vtable_handler_mappings($_, :local(1));
371+
for %map {
372+
unless %mapping{$_.key} {
373+
%mapping{$_.key} := $_.value;
374+
}
375+
}
376+
}
377+
if +%mapping {
378+
pir::stable_publish_vtable_handler_mapping__vPP($obj, %mapping);
379+
}
380+
}
357381
##
358382
## Introspecty
359383
##
@@ -394,6 +418,10 @@ knowhow NQPClassHOW {
394418
%!parrot_vtable_mapping
395419
}
396420

421+
method parrot_vtable_handler_mappings($obj, :$local!) {
422+
%!parrot_vtable_handler_mapping
423+
}
424+
397425
##
398426
## Checky
399427
##

src/ops/nqp.ops

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,57 @@ inline op stable_publish_vtable_mapping(in PMC, in PMC) :base_core {
725725
"Can only use stable_publish_vtable_mapping with a SixModelObject");
726726
}
727727

728+
/*
729+
=item publish_vtable_handler_mapping()
730+
731+
Publishes a Parrot v-table handler mapping, which will be hung off the s-table.
732+
It's stored as an array, so lookups will be speedy.
733+
734+
=cut
735+
736+
*/
737+
inline op stable_publish_vtable_handler_mapping(in PMC, in PMC) :base_core {
738+
if ($1->vtable->base_type == smo_id) {
739+
INTVAL i;
740+
741+
/* Get s-table and iterator over the mapping. */
742+
STable *st = STABLE($1);
743+
PMC *it = VTABLE_get_iter(interp, $2);
744+
745+
/* Toss any exist mapping array; allocate new one. */
746+
if (st->parrot_vtable_handler_mapping)
747+
mem_sys_free(st->parrot_vtable_handler_mapping);
748+
st->parrot_vtable_handler_mapping = mem_allocate_n_zeroed_typed(NUM_VTABLE_FUNCTIONS + PARROT_VTABLE_LOW, ParrotVtableHandlerSlot);
749+
750+
/* Go through the various mapped names and insert them into the
751+
* mapping table. */
752+
while (VTABLE_get_bool(interp, it)) {
753+
STRING *name = VTABLE_shift_string(interp, it);
754+
char *c_name = Parrot_str_to_cstring(interp, name);
755+
PMC *slot = VTABLE_get_pmc_keyed_str(interp, $2, name);
756+
INTVAL idx = -1;
757+
for (i = PARROT_VTABLE_LOW; i < NUM_VTABLE_FUNCTIONS + PARROT_VTABLE_LOW; i++) {
758+
if (strcmp(Parrot_vtable_slot_names[i], c_name) == 0) {
759+
idx = i;
760+
break;
761+
}
762+
}
763+
if (idx >= 0) {
764+
st->parrot_vtable_handler_mapping[idx].class_handle = VTABLE_get_pmc_keyed_int(interp,slot,0);
765+
st->parrot_vtable_handler_mapping[idx].att_name = VTABLE_get_string_keyed_int(interp,slot,1);
766+
}
767+
else
768+
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
769+
"No such Parrot v-table '%Ss'", name);
770+
}
771+
772+
PARROT_GC_WRITE_BARRIER(interp, STABLE_PMC($1));
773+
}
774+
else
775+
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
776+
"Can only use stable_publish_vtable_handler_mapping with a SixModelObject");
777+
}
778+
728779
/*
729780

730781
=item nqp_get_sc_object()

0 commit comments

Comments
 (0)