Okay, here's a quick rundown on PMCs and how we're handling opcodes called on PMC registers. (This is mildly different than what's gone in the past, FWIW)
Every PMC has a set of static types, stored in the vtable. These types are static, and stuck in the base vtable structure, which looks like: struct _vtable { PACKAGE *package; INTVAL base_type; INTVAL int_type; INTVAL float_type; INTVAL num_type; INTVAL string_type; void *(*vtable_funcs[VTABLE_SIZE])() } (cdecl's responsible for the function pointer table declaration, so I expect it's right for what I told it, but I might've told it wrong) There are several entries for each function, and the one that's called depends on the type of the second argument. The types are: base_type: A unique identifier attached to the package. 0-INTVAL_MAX int_type: 0, 1, 2, 3 for "same as you", native int, bigint, object float_type: 0, 1, 2, 3 for "same as you", native float, bigfloat, object num_type: 0, 1, 2, 3, 4, 5 for "same as you", native int, bigint, native float, bigfloat, object string_type: 0, 1, 2, 3, 4 for "same as you", native string, unicode, other, object The 'object' entry is used when a PMC isn't willing to classify itself definitively as a string, integer, float, or number type. In that case a multimethod dispatch is generally used to find out what the 'right' thing to do is, though the vtable code is allowed to just say "Give me yourself as an integer, darn it!" for a simple add: $foo = $bar + $baz; the assembly looks like (assuming we've got $foo, $bar, and $baz in registers already): add P0, P1, P2 the call will be: P1->vtable_funcs[VTABLE_ADD + P2->num_type](P1, P2, P0); and inside the add function P0 gets its "assign to" vtable method called, in case $foo's been overloaded. Which type an entry group takes depends on the entry. Concat takes strings, math ops take numbers, and so on. Now, that does mean we have a lot of vtable entries. At the moment I'm OK with that, though if it turns out that having a single ADD entry that does lots of checking is a win over a half-dozen different special-purpose add functions, we'll do that. There's a list of proposed vtable functions kicking around. We'll start with simple ones and go from there. References have a fancy reflecting vtable that vectors (when appropriate) through the vtable of the referent. But we'll get to that another time. Now, I'm sure you're all thinking "But what about aggregates?" (No, really, you were. You just might not've known it... :) Well, that's where things get interesting. Because we can't guarantee that individual entries in an array actually have PMCs attached to them, we vector all access to aggregate entries through the aggregate's vtable and leave that vtable to sort things out. Each type (int, float, num, string) has an entry past 'object' that's special. That function is still an add, subtract, concat, or whatever, but each of the three PMC pointers gets a corresponding key structure passed with it. A key structure looks like: struct key { INTVAL count; INTVAL type1; INTVAL type2; struct key *chain; union entry {STRING *skey1; INTVAL ikey1; PMC *pkey1; } union {STRING *skey2; INTVAL ikey2; PMC *pkey2; } } (Though we may make the individual key unions an array, assuming we don't hack this down to a single key) We pass in one per parameter, with a NULL meaning "No, I'm a scalar and not an aggregate". If two entries aren't enough the chain is used to point to another pair of keys. (Or another single key if we ditch the pairs) The "Access aggregate entries" then uses the key structure to find the appropriate entry in the aggregate to work on (The aggregate stuff's a little odd, and subject to change, but I think this is what we'll end up with) Questions, anyone? ;-) Dan --------------------------------------"it's like this"------------------- Dan Sugalski even samurai [EMAIL PROTECTED] have teddy bears and even teddy bears get drunk