Skip to content

Commit

Permalink
add pasmserializer pmc
Browse files Browse the repository at this point in the history
  • Loading branch information
plobsing committed Jan 4, 2011
1 parent 84a7d28 commit 7e145a8
Show file tree
Hide file tree
Showing 2 changed files with 308 additions and 0 deletions.
240 changes: 240 additions & 0 deletions src/pmc/pasmserializer.pmc
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
/*
Copyright (C) 2010, Parrot Foundation.
$Id$

=head1

src/pmc/pasmserializer - PASM Object Serializer

=head1 DESCRIPTION

Freezes and thaws PMCs using a text format suitable for use in PASM.

=head2 Vtables

=over 4

=cut

*/

/* HEADERIZER HFILE: none */

pmclass PASMSerializer auto_attrs {
ATTR PMC *buffer;
ATTR PMC *seen;
ATTR PMC *todo;
ATTR UINTVAL id;
ATTR INTVAL action;

/*

=item C<void init()>

Initialize the serializer.

=cut

*/

VTABLE void init() {
PARROT_PASMSERIALIZER(SELF)->buffer = PMCNULL;
PARROT_PASMSERIALIZER(SELF)->todo = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
PARROT_PASMSERIALIZER(SELF)->seen = PMCNULL;
PARROT_PASMSERIALIZER(SELF)->id = 0;

PObj_custom_mark_SET(SELF);
}

/*

=item C<void mark()>

Mark the PMC as alive.

=cut

*/

VTABLE void mark() {
Parrot_gc_mark_PMC_alive(INTERP, PARROT_PASMSERIALIZER(SELF)->buffer);
Parrot_gc_mark_PMC_alive(INTERP, PARROT_PASMSERIALIZER(SELF)->todo);
Parrot_gc_mark_PMC_alive(INTERP, PARROT_PASMSERIALIZER(SELF)->seen);
}

/*

=item C<PMC *get_iter()>

Get the C<todo> list for this freeze/thaw for iterating over.

=cut

*/

VTABLE PMC *get_iter() {
return PARROT_PASMSERIALIZER(SELF)->todo;
}

/*

=item C<INTVAL get_integer()>

Get the flags describing this visit action

=cut

*/

VTABLE INTVAL get_integer() {
return PARROT_PASMSERIALIZER(SELF)->action;
}

/*

=item C<void push_integer(INTVAL v)>

=item C<void push_float(FLOATVAL v)>

=item C<void push_string(STRING *v)>

=item C<void push_pmc(PMC *v)>

Push data item C<v> onto the end of the image being frozen.

=cut

*/

VTABLE void push_integer(INTVAL v) {
PMC *buf = PARROT_PASMSERIALIZER(SELF)->buffer;
VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, " "));
VTABLE_push_string(INTERP, buf, Parrot_str_from_int(INTERP, v));
VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, " "));
}

VTABLE void push_float(FLOATVAL v) {
PMC *buf = PARROT_PASMSERIALIZER(SELF)->buffer;
VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, " "));
VTABLE_push_string(INTERP, buf, Parrot_str_from_num(INTERP, v));
VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, " "));
}

VTABLE void push_string(STRING *v) {
PMC *buf = PARROT_PASMSERIALIZER(SELF)->buffer;
VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, " "));
if (STRING_IS_NULL(v)) {
VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, "STRINGNULL"));
}
else {
VTABLE_push_string(INTERP, buf,
Parrot_encoding_name(INTERP, Parrot_encoding_number_of_str(INTERP, v)));
VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, ":\""));
VTABLE_push_string(INTERP, buf, Parrot_str_escape(INTERP, v));
VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, "\""));
}
VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, " "));
}

VTABLE void push_pmc(PMC *v) {
PMC *buf = PARROT_PASMSERIALIZER(SELF)->buffer;
PMC *seen = PARROT_PASMSERIALIZER(SELF)->seen;
INTVAL id;
INTVAL was_seen;

VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, " "));

if (PMC_IS_NULL(v)) {
id = 0;
was_seen = 1;
}
else {
was_seen = VTABLE_exists_keyed(INTERP, seen, v);
if (was_seen)
id = VTABLE_get_integer_keyed(INTERP, seen, v);
else
id = ++PARROT_PASMSERIALIZER(SELF)->id;
}

VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, "$"));
VTABLE_push_string(INTERP, buf, Parrot_str_from_int(INTERP, id));

if (!was_seen) {
VTABLE_set_integer_keyed(INTERP, seen, v, id);
VTABLE_push_pmc(INTERP, PARROT_PASMSERIALIZER(SELF)->todo, v);

VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, ":"));
VTABLE_push_string(INTERP, buf, VTABLE_name(INTERP, v));
}

VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, " "));
}

/*

=item C<STRING *get_string()>

Get the serialized image as a string (after freezing).

=cut

*/

VTABLE STRING *get_string() {
return VTABLE_get_string(INTERP, PARROT_PASMSERIALIZER(SELF)->buffer);
}

/*

=item C<void set_pmc(PMC *p)>

Freeze the PMC C<p> into the buffer.

=cut

*/

VTABLE void set_pmc(PMC *p) {
PARROT_PASMSERIALIZER(SELF)->action = VISIT_FREEZE_NORMAL;
PARROT_PASMSERIALIZER(SELF)->buffer = Parrot_pmc_new(INTERP, enum_class_StringBuilder);
PARROT_PASMSERIALIZER(SELF)->seen = Parrot_pmc_new(INTERP, enum_class_Hash);
VTABLE_set_pointer(INTERP, PARROT_PASMSERIALIZER(SELF)->seen,
parrot_new_intval_hash(INTERP));
SELF.push_pmc(p);

// Parrot_visit_loop_visit(INTERP, SELF);
{
INTVAL i;
PMC *buf = PARROT_PASMSERIALIZER(SELF)->buffer;
PMC *todo = VTABLE_get_iter(INTERP, SELF);
for (i = 0; i < VTABLE_elements(INTERP, todo); i++) {
PMC *current = VTABLE_get_pmc_keyed_int(INTERP, todo, i);

VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, "\n$"));
VTABLE_push_string(INTERP, buf, Parrot_str_from_int(INTERP, i + 1));
VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, ":["));

VTABLE_freeze(INTERP, current, SELF);
VTABLE_visit(INTERP, current, SELF);
VISIT_PMC(INTERP, SELF, PMC_metadata(current));

VTABLE_push_string(INTERP, buf, CONST_STRING(INTERP, "]"));
}
}
}
}

/*

=back

=cut

*/

/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4:
*/
68 changes: 68 additions & 0 deletions t/pmc/pasmserializer.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!perl
# Copyright (C) 2011, Parrot Foundation.

use strict;
use warnings;
use lib qw[ . lib ../lib ../../lib ];
use Test::More;
use Parrot::Test tests => 2;


pir_output_like(<<'CODE', <<'OUT', 'PASMSerialize(FIA)');
.sub 'main' :main
$P0 = new ['FixedIntegerArray']
$P0 = 5
$P0[0] = 1
$P0[1] = 2
$P0[2] = 3
$P0[3] = 4
$P0[4] = 5
$P1 = new ['PASMSerializer']
setref $P1, $P0
$S0 = $P1
say $S0
.end
CODE
/
\s [$]1: FixedIntegerArray \s \n
[$]1: \[ \s (?: \d+ \s+ )+ [$]0 \s \] \n
/mx
OUT

pir_output_like(<<'CODE', <<'OUT', 'PASMSerialize(RPA)');
.sub 'main' :main
$P0 = new ['ResizablePMCArray']
$P0[0] = $P0
$P1 = box 42
$P2 = new ['Hash']
$P2['Hello World'] = $P1
$P2['Circular Ref'] = $P0
$P0[1] = $P1
$P0[2] = $P2
$P1 = new ['PASMSerializer']
setref $P1, $P0
$S0 = $P1
say $S0
.end
CODE
/
\s [$]1: ResizablePMCArray \s \n
(?:
[$]\d+: \[ \s (?: (?: -? \d+ (?: [.] \d+ )? (?: e \d+ )?
| \w+:"(?: [^"] | \\ ")*"
| STRINGNULL
| [$]\d+ (?: : \w+)?
)
\s+ )+ [$]0 \s \] \n
){3}
/mx
OUT

# Local Variables:
# mode: cperl
# cperl-indent-level: 4
# fill-column: 100
# End:
# vim: expandtab shiftwidth=4:

0 comments on commit 7e145a8

Please sign in to comment.