1 package Data::Dumper::ToXS;
3 our (%ix, %seen, $weaken);
5 sub _newix { $_[0].'['.($ix{$_[0]}++).']' }
6 sub _getglob { \*{$_[0]} }
8 use B qw(svref_2object cstring);
9 use Scalar::Util qw(refaddr isweak);
12 has target_package => (is => 'ro', required => 1);
14 has _to_generate => (is => 'ro', default => sub { [] });
17 my ($self, $name, $ref) = @_;
18 die "Generation target must be a reference" unless ref($ref);
19 push(@{$self->_to_generate}, [ $name => $ref ]);
24 my @do = @{$self->_to_generate};
25 join "\n\n", $self->_preamble,
26 (map $self->_generate_target(@$_), @do),
27 $self->_package_start($self->target_package),
28 (map $self->_generate_xsub($_->[0]), @do);
33 #define PERL_NO_GET_CONTEXT
42 my ($self, $package) = @_;
44 MODULE = ${package} PACKAGE = ${package}
52 my ($self, $name) = @_;
57 RETVAL = ${name}(aTHX);
63 sub _generate_target {
64 my ($self, $name, $ref) = @_;
65 local %ix = map +($_ => 0), qw(av hv sv);
68 my $first = _newix('sv');
69 my $body = $self->_dump_svrv($first, $ref);
70 my $vars = join '', map +(
71 $ix{$_} ? " ${\uc}* ${_}[$ix{$_}];\n" : ""
76 ${vars}${body}${weaken} return ${first};
82 my ($self, $ix, $ref) = @_;
84 $weaken .= " sv_rvweaken(${ix});\n" if isweak($_[2]);
86 # already seen this reference so make a copy
87 " ${ix} = newSVsv($seen{$ref});\n";
91 my $t_ix = _newix('sv');
93 $self->_dump_sv($t_ix, $ref),
94 " ${ix} = newRV_noinc(${t_ix});\n";
95 } elsif ($r eq 'HASH') {
96 my $t_ix = _newix('hv');
98 $self->_dump_hv($t_ix, $ref),
99 " ${ix} = newRV_noinc((SV *)${t_ix});\n";
100 } elsif ($r eq 'ARRAY') {
101 my $t_ix = _newix('av');
103 $self->_dump_av($t_ix, $ref),
104 " ${ix} = newRV_noinc((SV *)${t_ix});\n";
105 } elsif ($r eq 'REF') {
106 my $t_ix = _newix('sv');
108 $self->_dump_svrv($t_ix, $$ref),
109 " ${ix} = newRV_noinc(${t_ix});\n";
110 } elsif ($r eq 'CODE') {
111 my $full_name = join '::',
112 map $_->NAME, map +($_->GV->STASH, $_->GV), svref_2object($ref);
113 if (*{_getglob($full_name)}{CODE}||'' eq $ref) {
114 # GV_ADD strikes me as more likely to DWIM than to simply blow up
115 # if the generated routine gets called before the method is declared.
116 " ${ix} = newRV_inc((SV *) get_cv(${\cstring $full_name}, GV_ADD));\n";
118 die "Can't find ${ref} at ${full_name}";
121 die "Can't handle reftype ${r}";
127 my ($self, $ix, $ref) = @_;
129 $self->_dump_svrv($ix, $$ref);
131 # Not a reference. What are we dumping?
132 my $sv = svref_2object($ref);
133 if (!defined($$ref)) {
134 " ${ix} = newSVsv(&PL_sv_undef);\n";
135 } elsif ($sv->isa('B::IV')) {
136 " ${ix} = newSViv(".$sv->int_value.");\n";
137 } elsif ($sv->isa('B::NV')) {
138 " ${ix} = newSVnv(".$sv->NV.");\n";
139 } elsif ($sv->isa('B::PV')) {
140 " ${ix} = newSVpvs(".cstring($$ref).");\n";
142 die "Unsure how to dump ".$$ref;
148 my ($self, $ix, $ref) = @_;
150 " ${ix} = newHV();\n",
152 my $t_ix = _newix('sv');
153 ($self->_dump_sv($t_ix, \($ref->{$_})),
154 " hv_stores(${ix}, ${\cstring $_}, ${t_ix});\n")
159 my ($self, $ix, $ref) = @_;
161 " ${ix} = newAV();\n",
163 my $t_ix = _newix('sv');
164 $self->_dump_sv($t_ix, \($ref->[$_])),
165 " av_push(${ix}, ${t_ix});\n"