Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add invocation spec.
This is a (porting friendly) way to specify how an object handles being
invoked if it's not directly a code-ref.
  • Loading branch information
jnthn committed Feb 1, 2013
1 parent aaf85c3 commit 6005a68
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 16 deletions.
11 changes: 11 additions & 0 deletions src/6model/sixmodelobject.h
Expand Up @@ -36,6 +36,13 @@ typedef struct {
PMC *fetch_method;
} ContainerSpec;

/* How do we invoke this thing? Specifies either an attribute to look at for
* an invokable thing, or alternatively a method to call. */
typedef struct {
AttributeIdentifier value_slot;
PMC *invocation_handler;
} InvocationSpec;

/* How do we turn something of this type into a boolean? */
typedef struct {
INTVAL mode;
Expand Down Expand Up @@ -121,6 +128,10 @@ struct SixModel_STable {
* be taken as a "not a container" indication. */
ContainerSpec *container_spec;

/* If this is invokable, then this contains information needed to
* figure out how to invoke it. If not, it'll be null. */
InvocationSpec *invocation_spec;

/* Information - if any - about how we can turn something of this type
* into a boolean. */
BoolificationSpec *boolification_spec;
Expand Down
2 changes: 2 additions & 0 deletions src/QAST/Operations.nqp
Expand Up @@ -1620,6 +1620,8 @@ QAST::Operations.add_core_pirop_mapping('setmethcache', 'publish_method_cache',
QAST::Operations.add_core_pirop_mapping('setmethcacheauth', 'set_method_cache_authoritativeness', '0Pi', :inlinable(1));
QAST::Operations.add_core_pirop_mapping('settypecache', 'publish_type_check_cache', '0PP', :inlinable(1));
QAST::Operations.add_core_pirop_mapping('objprimspec', 'repr_get_primitive_type_spec', 'IP', :inlinable(1));
QAST::Operations.add_core_pirop_mapping('setcontspec', 'set_container_spec', '0PPsP', :inlinable(1));
QAST::Operations.add_core_pirop_mapping('setinvokespec', 'set_invocation_spec', '0PPsP', :inlinable(1));

# lexical related opcodes
QAST::Operations.add_core_pirop_mapping('getlex', 'find_lex', 'Ps');
Expand Down
39 changes: 39 additions & 0 deletions src/ops/nqp.ops
Expand Up @@ -2128,6 +2128,45 @@ inline op set_container_spec(invar PMC, invar PMC, in STR, invar PMC) :base_core
}


/*

=item set_invocation_spec

Sets the invocation spec for the type in $1 (it actaully sets it on
the s-table, so the type object or any instance of the type will do).

Either set $2 and $3 to a class handle and an attribute name (which
should contain a code ref when looked up), or set $4 to a code ref
that will handle the invocation. $2/$3 take precedence over $4.

=cut

*/
inline op set_invocation_spec(invar PMC, invar PMC, in STR, invar PMC) :base_core {
PMC *target = decontainerize(interp, $1);
if ($1->vtable->base_type == smo_id) {
STable *st = STABLE($1);

/* Allocate and populate new invocation spec. */
InvocationSpec *new_spec = mem_allocate_zeroed_typed(InvocationSpec);
new_spec->value_slot.class_handle = $2;
new_spec->value_slot.attr_name = $3;
new_spec->invocation_handler = $4;

/* Free any existing spec and put the new one in place. */
if (st->invocation_spec)
mem_sys_free(st->invocation_spec);
st->invocation_spec = new_spec;
PARROT_GC_WRITE_BARRIER(interp, STABLE_PMC($1));
/*ST_SC_WRITE_BARRIER(st);*/
}
else {
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
"Can only use set_invocation_spec with a SixModelObject");
}
}


/*

=item set_boolification_spec
Expand Down
49 changes: 33 additions & 16 deletions src/pmc/sixmodelobject.pmc
Expand Up @@ -692,24 +692,41 @@ pmclass SixModelObject manual_attrs dynpmc group nqp {

VTABLE opcode_t *invoke(void *next) {
PMC *decont = decontainerize(interp, SELF);
PMC **vt = STABLE(decont)->parrot_vtable_mapping;
PMC *meth;
AttributeIdentifier *vth = STABLE(decont)->parrot_vtable_handler_mapping;
if (vt && !PMC_IS_NULL(meth = vt[PARROT_VTABLE_SLOT_INVOKE])) {
PMC *cur_ctx = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
VTABLE_unshift_pmc(interp, cur_ctx, decont);
Parrot_pcc_invoke_from_sig_object(interp, meth, cur_ctx);
return (opcode_t *)next;

/* First, see if we've an invocation spec. */
InvocationSpec *is = STABLE(decont)->invocation_spec;
if (is) {
if (is->value_slot.class_handle) {
PMC *val = get_attr(interp, decont, is->value_slot.class_handle,
is->value_slot.attr_name, is->value_slot.hint);
return VTABLE_invoke(interp, val, next);
}
else {
return VTABLE_invoke(interp, is->invocation_handler, next);
}
}
else if (vth && vth[PARROT_VTABLE_SLOT_INVOKE].class_handle) {
PMC *val = get_attr(interp, decont,
vth[PARROT_VTABLE_SLOT_INVOKE].class_handle,
vth[PARROT_VTABLE_SLOT_INVOKE].attr_name,
vth[PARROT_VTABLE_SLOT_INVOKE].hint);
return VTABLE_invoke(interp, val, next);

/* Otherwise - for back-compat - fall back to Parrot v-table mapping. */
else {
PMC **vt = STABLE(decont)->parrot_vtable_mapping;
PMC *meth;
AttributeIdentifier *vth = STABLE(decont)->parrot_vtable_handler_mapping;
if (vt && !PMC_IS_NULL(meth = vt[PARROT_VTABLE_SLOT_INVOKE])) {
PMC *cur_ctx = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
VTABLE_unshift_pmc(interp, cur_ctx, decont);
Parrot_pcc_invoke_from_sig_object(interp, meth, cur_ctx);
return (opcode_t *)next;
}
else if (vth && vth[PARROT_VTABLE_SLOT_INVOKE].class_handle) {
PMC *val = get_attr(interp, decont,
vth[PARROT_VTABLE_SLOT_INVOKE].class_handle,
vth[PARROT_VTABLE_SLOT_INVOKE].attr_name,
vth[PARROT_VTABLE_SLOT_INVOKE].hint);
return VTABLE_invoke(interp, val, next);
}
else
return SUPER(next);
}
else
return SUPER(next);
}

VTABLE PMC * get_iter() {
Expand Down

0 comments on commit 6005a68

Please sign in to comment.