Continuing the discussion from How do I trace error? @jamshark70 @jordan
Object:perform usually process an Array whose first element is a Symbol (‘selector’), with exceptions without a symbol.
First, expects its first element to be a Symbol acting as the ‘selector’. However, the method also handles cases where the selector is not a symbol. Such flexibility, while powerful to play with other things, introduces complexity and can indeed be a source of bugs and terrible error messages.
–The last bug we talked about here was with RawArray subclasses, on the other thread. Where it just checks the selector, and does not do any kind of type checking on the actual values.–
my comments (any mistake is my bad)
// Function to "do stuff on objs"
int objectPerform(struct VMGlobals *g, int numArgsPushed)
{
// Making some vars to hold
PyrSlot *recvrSlot, *selSlot, *listSlot;
PyrSlot *pslot, *qslot;
PyrSymbol *selector;
int m, mmax;
// Figuring out where the message's meant to go based on args
recvrSlot = g->sp - numArgsPushed + 1;
// Selector's the next dude?
selSlot = recvrSlot + 1;
if (IsSym(selSlot)) { // If selector's a symbol, we're cool
selector = slotRawSymbol(selSlot); // Grab the actual symbol from the slot
// Gotta shuffle args down a slot to fill where selector was beforee
pslot = selSlot - 1;
qslot = selSlot;
for (m=0; m<numArgsPushed - 2; ++m) slotCopy(++pslot, ++qslot);
g->sp --; // Fix the stack pointer
numArgsPushed--; // One less arg to worry bout
// Now it looks just like a normal msg
} else if (IsObj(selSlot)) { // If selector's an object...
listSlot = selSlot;
// If it's a list, we need to get its slots
if (slotRawObject(listSlot)->classptr == class_list) {
listSlot = slotRawObject(listSlot)->slots;
}
// If it ain't an object or ain't an array, it's no good
if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
goto badselector;
}
// Get the array from the list slot
PyrObject *array = slotRawObject(listSlot);
if (array->size < 1) { // Needs at least one selector inside
error("Array must have a selector.\n");
return errFailed;
}
selSlot = array->slots; // Grab the selector from array slots
selector = slotRawSymbol(selSlot); // Get the real symbol for selector
// Shuffle args if more than 2
if (numArgsPushed>2) {
qslot = recvrSlot + numArgsPushed;
pslot = recvrSlot + numArgsPushed + array->size - 2;
for (m=0; m<numArgsPushed - 2; ++m) slotCopy(--pslot, --qslot);
}
// Copy args from array to where they go
pslot = recvrSlot;
qslot = selSlot;
for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
// Fix the stack and how many args we're dealing
g->sp += array->size - 2;
numArgsPushed += array->size - 2;
// Setup's good, it seems... ?
// but it can also be very wrong, with wrong types in RawArray, for example
} else { // If selector's messed up, it's BAD
error("perform selector not a Symbol or Array.\n"); // Show us the problem.
dumpObjectSlot(selSlot); // better error messages, babe..((
return errWrongType;
}
// Finally, send the msg with the selecto, and arg count
sendMessage(g, selector, numArgsPushed);
g->numpop = 0; // Reset the pop count
return errNone;
// that's an intricate path... ))) the upside is that it's flexible
That’s an intricate path… ))) the upside is that it’s flexible. That’s what we want? But can’t it be improved? RawArray is a case to improve, for example. Many alternatives are possible, of course.