Sean O'Rourke:
# On Wed, 4 Sep 2002, Brent Dax wrote:
# > What if (say) @b is a two-dimensional array?
# 
# Then you get "interesting values of undef" :).  Seriously, I 
# suspect one of the following:
# 
# 1 - runtime error
# 2 - each row (or column) of @b numified to its length
# 3 - the first element of each row/col of @b
# 4 - the other arrays boosted to the highest dimension
# 
# I like #2, because it is easy and keeps hyper-operation 
# simple.  If those aren't just numeric operators, but some 

It's already been defined to be #4.  My point was that we can't just
render it into bytecode that directly, unless all the arrays are typed
(in which case we know the dimensionality).

I'd imagine that we'll have to have an opcode like:

        hyper P0, P1, P2, LABEL

Where P0 is the result, P1 and P2 are the operands, and P31 is a sub
like:

        pushp
        restore P1
        restore P2
        new P0, .PerlUndef
        add P0, P1, P2
        save P0
        popp
        ret

Thus, for the given case:

        # @a = @b ^+ @c ^+ @d
        find_global P1, "@a"
        find_global P2, "@b"
        find_global P3, "@c"
        find_global P4, "@d"

        hyper P0, P3, P4, ONE
        hyper P0, P2, P0, TWO
        assign P1, P0

ONE:
        pushp
        restore P1
        restore P2
        new P0, .PerlNum
        add P0, P1, P2
        save P0
        popp
        ret

TWO:
        pushp
        restore P1
        restore P2
        new P0, .PerlNum
        add P0, P1, P2
        save P0
        popp
        ret

(though a real compiler would fold those into one.)

Here's a rough implementation of hyper_p_p_p_ic.  I may be using some
imaginary vtable functions, though.  :^)

        op hyper(out PMC, in PMC, in PMC, in INT) {
                $1=do_hyper($2, $3, $4);
        }

        static PMC* do_hyper(PMC* left, PMC* right, opcode_t *func) {
                INTVAL n;
                PMC* ret;
                
                if(left->vtable->dimensions() >
right->vtable->dimensions) {
                        ret=pmc_new(enum_class_Array);
                        
                        for(n=0; n < left->vtable->length(); n++) {
                                /*
                                ** Instead of actually creating a PMC of
the correct dimensionality,
                                ** I recursively remove one level of
dimensionality from the higher-
                                ** dimension PMC, thus avoiding extra
allocations.
                                ** 
                                ** XXX This *does* work in all cases,
right?
                                */
                                
        
ret->vtable->push_pmc(do_hyper(left->vtable->get_pmc_keyed_integer(n),
right, func));
                        }
                }
                else if(left->vtable->dimensions() <
right->vtable->dimensions()) {
                        ret=pmc_new(enum_class_Array);
                        
                        for(n=0; n < right->vtable->length(); n++) {
                                ret->vtable->push_pmc(do_hyper(left,
right->vtable->get_pmc_keyed_integer(n), func));
                        }
                }
                else if(left->vtable->dimensions() != 1) {
                        ret=pmc_new(enum_class_Array);
                        
                        if(left->vtable->length() <
right->vtable->length()) {
        
left->vtable->extend(right->vtable->length());
                        }
                        else if(left->vtable->length() >
right->vtable->length()) {
        
right->vtable->extend(left->vtable->length());
                        }
                        
                        for(n=0; n < left->vtable->length(); n++) {
                                ret->vtable->push_pmc(do_hyper(
        
left->vtable->get_pmc_keyed_integer(n),
        
right->vtable->get_pmc_keyed_integer(n),
                                        func
                                ));
                        }
                }
                else {
                        stack_push(
                                interpreter,
                                &interpreter->ctx.user_stack, 
                                right,
                                STACK_ENTRY_PMC,
                                STACK_CLEANUP_NULL
                        );

                        stack_push(
                                interpreter,
                                &interpeter->ctx.user_stack,
                                left,
                                STACK_ENTRY_PMC,
                                STACK_CLEANUP_NULL
                        );
                                
                        runops(interpreter, func);
                                
                        stack_pop(
                                interpreter,
                                &interpreter->ctx.user_stack,
                                &ret,
                                STACK_ENTRY_PMC
                        );
                }
                
                return ret;
        }

--Brent Dax <[EMAIL PROTECTED]>
@roles=map {"Parrot $_"} qw(embedding regexen Configure)

"In other words, it's the 'Blow up this Entire Planet and Possibly One
or Two Others We Noticed on our Way Out Here' operator."
    --Damian Conway

Reply via email to