Skip to content

Commit

Permalink
Get hash slices essentially working. In the process, move Associative…
Browse files Browse the repository at this point in the history
… role completely into the setting. Nothing in PIR actually did it, plus we now have the ability to augment the role into classes in the core setting anyway, so it's no problem to add to things first defined in PIR anyway. Slight re-think of how we handle non-Perl 6 hashes that seems rather cleaner to me; need to tweak array indexing similarly, will do it soon.
  • Loading branch information
jnthn committed Apr 19, 2010
1 parent 346e76d commit 35bcd52
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 93 deletions.
1 change: 1 addition & 0 deletions build/Makefile.in
Expand Up @@ -165,6 +165,7 @@ CORE_SOURCES = \
src/cheats/trait-export.pm \
src/cheats/num.pm \
src/cheats/eval.pm \
src/core/Associative.pm \
src/core/Mu.pm \
src/core/Bool.pm \
src/core/Parcel.pm \
Expand Down
28 changes: 23 additions & 5 deletions src/Perl6/Actions.pm
Expand Up @@ -2187,13 +2187,31 @@ method postcircumfix:sym<[ ]>($/) {

method postcircumfix:sym<{ }>($/) {
my $past := PAST::Op.new( :name('!postcircumfix:<{ }>'), :pasttype('call'), :node($/) );
if $<semilist><statement> { $past.push($<semilist>.ast); }
if $<semilist><statement> {
if +$<semilist><statement> > 1 {
$/.CURSOR.panic("Sorry, multi-dimensional indexes are not yet supported");
}
my $slast := $<semilist>.ast;
if $slast[0].isa(PAST::Op) && $slast[0].name eq '&infix:<,>' {
for @($slast[0]) { $past.push($_); }
}
else {
$past.push($slast);
}
}
make $past;
}

method postcircumfix:sym<ang>($/) {
make PAST::Op.new( $<quote_EXPR>.ast, :name('!postcircumfix:<{ }>'),
:pasttype('call'), :node($/) );
my $past := PAST::Op.new( :name('!postcircumfix:<{ }>'), :pasttype('call'), :node($/) );
my $quoted := $<quote_EXPR>.ast;
if $quoted.isa(PAST::Stmts) && $quoted[0].isa(PAST::Op) && $quoted[0].name() eq '&infix:<,>' {
for @($quoted[0]) { $past.push($_); }
}
else {
$past.push($quoted);
}
make $past;
}

method postcircumfix:sym<( )>($/) {
Expand Down Expand Up @@ -2599,9 +2617,9 @@ sub create_code_object($block, $type, $multiness, $lazy_init) {
:name('new'),
PAST::Var.new( :name(@name.pop), :namespace(@name), :scope('package') ),
$block,
$multiness,
$lazy_init
$multiness
);
if $lazy_init { $past.push($lazy_init) }
$past<past_block> := $block;
$past
}
Expand Down
2 changes: 1 addition & 1 deletion src/Perl6/Grammar.pm
Expand Up @@ -1561,7 +1561,7 @@ token postcircumfix:sym<{ }> {
}

token postcircumfix:sym<ang> {
<?[<]> <quote_EXPR: ':q'>
<?[<]> <quote_EXPR: ':q', ':w'>
<O('%methodcall')>
}

Expand Down
99 changes: 15 additions & 84 deletions src/builtins/Associative.pir
Expand Up @@ -6,98 +6,20 @@ src/classes/Associative.pir - Associative Role

=head1 DESCRIPTION

=cut

.namespace ['Associative[::T]']

.sub '' :load :init
# Create a parametric role with 1 possible candidate.
.local pmc role
.const 'Sub' $P0 = '_Associative_role_body'
role = new ['Perl6Role']
$P1 = box 'Associative'
setattribute role, '$!shortname', $P1
role.'!add_variant'($P0)
set_hll_global 'Associative', role
.end


# This defines the body of the role, which is run per type the role is
# parameterized with.
.sub '' :anon :subid('_Associative_role_body')
.param pmc type :optional

# Need to capture the methods that belong in this role.
.const 'Sub' $P1 = 'Associative::of'
capture_lex $P1

# Capture type.
if null type goto no_type
type = type.'WHAT'()
goto type_done
no_type:
type = get_hll_global 'Mu'
type_done:
.lex 'T', type

# Create role.
.tailcall '!create_parametric_role'("Associative[::T]")
.end
.sub '' :load :init
.local pmc block, signature
.const 'Sub' $P0 = '_Associative_role_body'
block = $P0
signature = allocate_signature 1
setprop block, "$!signature", signature
null $P1
set_signature_elem signature, 0, "T", SIG_ELEM_IS_OPTIONAL, $P1, $P1, $P1, $P1, $P1, $P1, ""
.end


=head2 Methods

=over

=item postcircumfix:<{ }>
Actually these days, Associative is defined in Perl 6 and this is
just a postcircumfix:<{ }> for non-Perl 6 types mapper.

=cut

.namespace ['Associative[::T]']
.sub 'postcircumfix:<{ }>' :method :multi(_, _)
.param pmc key
.local pmc result
result = self[key]
unless null result goto have_result
result = new ['Perl6Scalar']
have_result:
.return (result)
.end

=item of

Returns the type constraining what may be stored.

=cut

.sub 'of' :method :outer('_Associative_role_body') :subid('Associative::of')
$P0 = find_lex 'T'
.return ($P0)
.end
.sub '' :load :init
.local pmc block, signature
.const 'Sub' block = 'Associative::of'
signature = allocate_signature 0
setprop block, "$!signature", signature
.end

=item !postcircumfix:<{ }>

Because foreign (non-Rakudo) Parrot objects generally won't
understand the "postcircumfix:<{ }>" method, we generate
postcircumfix as a private call to this function, and this
function then delegates to the appropriate method. For PMCs
that don't have a postcircumfix:<{ }> method, we'll have to
fake it later.
function then delegates to the appropriate method. In the
case we want a single value, then it just does the lookup;
otherwise, we rely on the method dispatches for the complex
cases looping back to here to get the one value.
=cut
Expand All @@ -110,6 +32,15 @@ fake it later.
$I0 = isa invocant, 'Mu'
if $I0 goto object_method
foreign:
$I0 = elements args
if $I0 != 1 goto delegate
$P0 = args[0]
$P0 = invocant[$P0]
unless null $P0 goto done
$P0 = new ['Perl6Scalar']
done:
.return ($P0)
delegate:
# XXX relies on the method being in the namespace -- perhaps
# should use method lookup instead
$P0 = get_hll_global ['Associative[::T]'], 'postcircumfix:<{ }>'
Expand Down
6 changes: 5 additions & 1 deletion src/builtins/Code.pir
Expand Up @@ -31,7 +31,7 @@ for executable objects.
.sub 'new' :method
.param pmc do
.param pmc multi
.param pmc lazy_sig_init
.param pmc lazy_sig_init :optional
$P0 = getprop '$!p6type', do
if null $P0 goto need_create
.return ($P0)
Expand Down Expand Up @@ -171,6 +171,7 @@ Gets the signature for the block, or returns Failure if it lacks one.
# No signautre yet, but maybe we have a lazy creator.
lazy_sig = getattribute self, '$!lazy_sig_init'
if null lazy_sig goto srsly_no_sig
push_eh lazyerr
ll_sig = lazy_sig()
setprop do, '$!signature', ll_sig
goto have_sig
Expand All @@ -183,6 +184,9 @@ Gets the signature for the block, or returns Failure if it lacks one.
$P1 = $P1.'new'('ll_sig' => ll_sig)
setattribute self, '$!signature', $P1
.return ($P1)
lazyerr:
pop_eh
say lazy_sig
.end

=item do()
Expand Down
18 changes: 18 additions & 0 deletions src/core/Associative.pm
@@ -0,0 +1,18 @@
role Associative[::T = Mu] {
our multi method postcircumfix:<{ }>() {
self.values()
}
our multi method postcircumfix:<{ }>(*@keys) {
my $result = pir::new__ps('ResizablePMCArray');
for @keys {
pir::push($result, self{$_})
}
Q:PIR {
$P0 = find_lex '$result'
.tailcall '&infix:<,>'($P0 :flat)
}
}
method of() {
T
}
}
2 changes: 1 addition & 1 deletion src/core/EnumMap.pm
Expand Up @@ -5,7 +5,7 @@ class EnumMap does Associative {
self.bless(*, storage => pir::getattribute__PPs(%values, '$!storage'));
}

method postcircumfix:<{ }>($key) {
multi method postcircumfix:<{ }>($key) {
Q:PIR {
.local pmc self
self = find_lex 'self'
Expand Down
2 changes: 1 addition & 1 deletion src/core/Hash.pm
@@ -1,5 +1,5 @@
role Hash is EnumMap {
method postcircumfix:<{ }>($key) {
multi method postcircumfix:<{ }>($key) {
Q:PIR {
.local pmc self
self = find_lex 'self'
Expand Down
1 change: 1 addition & 0 deletions src/core/traits.pm
Expand Up @@ -12,6 +12,7 @@ our multi trait_mod:<is>(Mu $child, Role $r) {
$child.^add_parent($r!select!pun);
}

role Associative { ... }
our multi trait_mod:<of>(ContainerDeclarand $cont, Mu \$type) {
given substr($cont.name, 0, 1) {
when '@' { $cont.container does Positional[$type] }
Expand Down

0 comments on commit 35bcd52

Please sign in to comment.