void fxSlotToID(txMachine* the, txSlot* slot, txInteger* id) { txString string; txSlot* key; again: if ((slot->kind == XS_INTEGER_KIND) && fxIntegerToIndex(the->dtoa, slot->value.integer, id)) return; if ((slot->kind == XS_NUMBER_KIND) && fxNumberToIndex(the->dtoa, slot->value.number, id)) return; if (slot->kind == XS_SYMBOL_KIND) { *id = slot->value.ID; return; } if (slot->kind == XS_REFERENCE_KIND) { fxToPrimitive(the, slot, XS_STRING_HINT); goto again; } string = fxToString(the, slot); if (!fxStringToIndex(the->dtoa, string, id)) { if (slot->kind == XS_STRING_X_KIND) key = fxNewNameX(the, string); else key = fxNewName(the, slot); *id = key->ID; } }
txInteger fxToInteger(txMachine* the, txSlot* theSlot) { #if mxOptimize if (XS_INTEGER_KIND == theSlot->kind) return theSlot->value.integer; // this is the case over 90% of the time, so avoid the switch #endif again: switch (theSlot->kind) { case XS_UNDEFINED_KIND: case XS_NULL_KIND: theSlot->kind = XS_INTEGER_KIND; theSlot->value.integer = 0; break; case XS_BOOLEAN_KIND: theSlot->kind = XS_INTEGER_KIND; if (theSlot->value.boolean == 0) theSlot->value.integer = 0; else theSlot->value.integer = 1; break; case XS_INTEGER_KIND: break; case XS_NUMBER_KIND: theSlot->kind = XS_INTEGER_KIND; switch (c_fpclassify(theSlot->value.number)) { case C_FP_INFINITE: case C_FP_NAN: case C_FP_ZERO: theSlot->value.integer = 0; break; default: { #define MODULO 4294967296.0 txNumber aNumber = c_fmod(c_trunc(theSlot->value.number), MODULO); if (aNumber >= MODULO / 2) aNumber -= MODULO; else if (aNumber < -MODULO / 2) aNumber += MODULO; theSlot->value.integer = (txInteger)aNumber; } break; } break; case XS_STRING_KIND: case XS_STRING_X_KIND: theSlot->kind = XS_NUMBER_KIND; theSlot->value.number = fxStringToNumber(the->dtoa, theSlot->value.string, 1); goto again; case XS_SYMBOL_KIND: mxTypeError("Cannot coerce symbol to integer"); break; case XS_REFERENCE_KIND: fxToPrimitive(the, theSlot, XS_NUMBER_HINT); goto again; default: mxTypeError("Cannot coerce to integer"); break; } return theSlot->value.integer; }
txNumber fxToNumber(txMachine* the, txSlot* theSlot) { again: switch (theSlot->kind) { case XS_UNDEFINED_KIND: theSlot->kind = XS_NUMBER_KIND; theSlot->value.number = C_NAN; break; case XS_NULL_KIND: theSlot->kind = XS_NUMBER_KIND; theSlot->value.number = 0; break; case XS_BOOLEAN_KIND: theSlot->kind = XS_NUMBER_KIND; if (theSlot->value.boolean == 0) theSlot->value.number = 0; else theSlot->value.number = 1; break; case XS_INTEGER_KIND: theSlot->kind = XS_NUMBER_KIND; theSlot->value.number = theSlot->value.integer; break; case XS_NUMBER_KIND: break; case XS_STRING_KIND: case XS_STRING_X_KIND: theSlot->kind = XS_NUMBER_KIND; theSlot->value.number = fxStringToNumber(the->dtoa, theSlot->value.string, 1); break; case XS_SYMBOL_KIND: mxTypeError("Cannot coerce symbol to number"); break; case XS_REFERENCE_KIND: fxToPrimitive(the, theSlot, XS_NUMBER_HINT); goto again; default: mxTypeError("Cannot coerce to number"); break; } return theSlot->value.number; }
txSlot* fxAt(txMachine* the, txSlot* slot) { txIndex index; txString string; txSlot* key; again: if ((slot->kind == XS_INTEGER_KIND) && fxIntegerToIndex(the->dtoa, slot->value.integer, &index)) { slot->value.at.id = 0; slot->value.at.index = index; } else if ((slot->kind == XS_NUMBER_KIND) && fxNumberToIndex(the->dtoa, slot->value.number, &index)) { slot->value.at.id = 0; slot->value.at.index = index; } else if (slot->kind == XS_SYMBOL_KIND) { slot->value.at.id = slot->value.symbol; slot->value.at.index = XS_NO_ID; } else { if (slot->kind == XS_REFERENCE_KIND) { fxToPrimitive(the, slot, XS_STRING_HINT); goto again; } string = fxToString(the, slot); if (fxStringToIndex(the->dtoa, string, &index)) { slot->value.at.id = 0; slot->value.at.index = index; } else { if (slot->kind == XS_STRING_X_KIND) key = fxNewNameX(the, string); else key = fxNewName(the, slot); slot->value.at.id = key->ID; slot->value.at.index = XS_NO_ID; } } slot->kind = XS_AT_KIND; return slot; }
txString fxToString(txMachine* the, txSlot* theSlot) { char aBuffer[256]; again: switch (theSlot->kind) { case XS_UNDEFINED_KIND: fxCopyStringC(the, theSlot, "undefined"); break; case XS_NULL_KIND: fxCopyStringC(the, theSlot, "null"); break; case XS_BOOLEAN_KIND: if (theSlot->value.boolean == 0) fxCopyStringC(the, theSlot, "false"); else fxCopyStringC(the, theSlot, "true"); break; case XS_INTEGER_KIND: fxCopyStringC(the, theSlot, fxIntegerToString(the->dtoa, theSlot->value.integer, aBuffer, sizeof(aBuffer))); break; case XS_NUMBER_KIND: fxCopyStringC(the, theSlot, fxNumberToString(the->dtoa, theSlot->value.number, aBuffer, sizeof(aBuffer), 0, 0)); break; case XS_SYMBOL_KIND: mxTypeError("Cannot coerce symbol to string"); break; case XS_STRING_KIND: case XS_STRING_X_KIND: break; case XS_REFERENCE_KIND: fxToPrimitive(the, theSlot, XS_STRING_HINT); goto again; default: mxTypeError("Cannot coerce to string"); break; } return theSlot->value.string; }
txInteger fxSlotToIndex(txMachine* the, txSlot* slot, txIndex* index) { txString string; txSlot* key; again: if ((slot->kind == XS_INTEGER_KIND) && fxIntegerToIndex(the->dtoa, slot->value.integer, index)) return 0; if ((slot->kind == XS_NUMBER_KIND) && fxNumberToIndex(the->dtoa, slot->value.number, index)) return 0; if (slot->kind == XS_SYMBOL_KIND) return slot->value.symbol; if (slot->kind == XS_REFERENCE_KIND) { fxToPrimitive(the, slot, XS_STRING_HINT); goto again; } string = fxToString(the, slot); if (fxStringToIndex(the->dtoa, string, index)) return 0; if (slot->kind == XS_STRING_X_KIND) key = fxNewNameX(the, string); else key = fxNewName(the, slot); return key->ID; }
txUnsigned fxToUnsigned(txMachine* the, txSlot* theSlot) { txUnsigned result; again: switch (theSlot->kind) { case XS_UNDEFINED_KIND: case XS_NULL_KIND: theSlot->kind = XS_INTEGER_KIND; result = theSlot->value.integer = 0; break; case XS_BOOLEAN_KIND: theSlot->kind = XS_INTEGER_KIND; if (theSlot->value.boolean == 0) result = theSlot->value.integer = 0; else result = theSlot->value.integer = 1; break; case XS_INTEGER_KIND: if (theSlot->value.integer >= 0) return (txUnsigned)theSlot->value.integer; theSlot->kind = XS_NUMBER_KIND; theSlot->value.number = theSlot->value.integer; // continue case XS_NUMBER_KIND: theSlot->kind = XS_INTEGER_KIND; switch (c_fpclassify(theSlot->value.number)) { case C_FP_INFINITE: case C_FP_NAN: case C_FP_ZERO: result = theSlot->value.integer = 0; break; default: { #define MODULO 4294967296.0 txNumber aNumber = c_fmod(c_trunc(theSlot->value.number), MODULO); if (aNumber < 0) aNumber += MODULO; result = (txUnsigned)aNumber; if (((txInteger)result) >= 0) { theSlot->kind = XS_INTEGER_KIND; theSlot->value.integer = (txInteger)result; } else { theSlot->kind = XS_NUMBER_KIND; theSlot->value.number = aNumber; } } break; } break; case XS_STRING_KIND: case XS_STRING_X_KIND: theSlot->kind = XS_NUMBER_KIND; theSlot->value.number = fxStringToNumber(the->dtoa, theSlot->value.string, 1); goto again; case XS_SYMBOL_KIND: result = 0; mxTypeError("Cannot coerce symbol to unsigned"); break; case XS_REFERENCE_KIND: fxToPrimitive(the, theSlot, XS_NUMBER_HINT); goto again; default: result = 0; mxTypeError("Cannot coerce to unsigned"); break; } return result; }