Numeric::Ptr ATFloatOrDerivedImpl::atan(const DynamicContext* context) const { switch (_state) { case NaN: return this; case INF: return newFloat((MM_HALF_PI), context); case NEG_INF: return newFloat(MAPM(MM_HALF_PI).neg(), context); case NEG_NUM: case NUM: return newFloat(_float.atan(), context); default: assert(false); return 0; // should never get here } }
Numeric::Ptr ATFloatOrDerivedImpl::exp(const DynamicContext* context) const { switch (_state) { case NaN: return this; case INF: return infinity(context); case NEG_INF: return newFloat(0, context); case NEG_NUM: case NUM: return newFloat(_float.exp(), context); default: assert(false); return 0; // should never get here } }
/** Returns the mod of its operands as a Numeric */ Numeric::Ptr ATFloatOrDerivedImpl::mod(const Numeric::Ptr &other, const DynamicContext* context) const { if(other->getPrimitiveTypeIndex() == AnyAtomicType::DECIMAL) { // if other is a decimal, promote it to xs:float return this->mod((const Numeric::Ptr )other->castAs(this->getPrimitiveTypeIndex(), context), context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::DOUBLE) { // if other is a double, promote this to xs:double return ((const Numeric::Ptr )this->castAs(other->getPrimitiveTypeIndex(), context))->mod(other, context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::FLOAT) { // same primitive type, can make comparison const ATFloatOrDerivedImpl* otherImpl = (ATFloatOrDerivedImpl*)(const Numeric*)other; if(this->isNaN() || otherImpl->isNaN() || this->isInfinite() || otherImpl->isZero()) { return notANumber(context); } else if(otherImpl->isInfinite() || this->isZero()) { return (const Numeric::Ptr )this->castAs(AnyAtomicType::FLOAT, context); } else { MAPM result = _float; MAPM r; r = result.integer_divide(otherImpl->_float); result -= r * otherImpl->_float; if (result == 0 && isNegative()) return negZero(context); return newFloat(result, context); } } else { assert(false); // should never get here, numeric types are xs:decimal, xs:float, xs:integer and xs:double return 0; } }
/** Returns the Additive inverse of this Numeric */ Numeric::Ptr ATFloatOrDerivedImpl::invert(const DynamicContext* context) const { switch (_state) { case NaN: return this; case INF: return negInfinity(context); case NEG_INF: return infinity(context); case NEG_NUM: case NUM: if(this->isZero()) { if(this->isNegative()) return newFloat(0, context); else return negZero(context); } return newFloat(_float.neg(), context); default: assert(false); return 0; // should never get here } }
/** Returns a Numeric object which is the difference of this and * other */ Numeric::Ptr ATFloatOrDerivedImpl::subtract(const Numeric::Ptr &other, const DynamicContext* context) const { if(other->getPrimitiveTypeIndex() == AnyAtomicType::DECIMAL) { // if other is a decimal, promote it to xs:float return this->subtract((const Numeric::Ptr )other->castAs(this->getPrimitiveTypeIndex(), context), context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::DOUBLE) { // if other is a double, promote this to xs:double return ((const Numeric::Ptr )this->castAs(other->getPrimitiveTypeIndex(), context))->subtract(other, context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::FLOAT) { // same primitive type, can make comparison ATFloatOrDerivedImpl* otherImpl = (ATFloatOrDerivedImpl*)(const Numeric*)other; if(otherImpl->_state == NaN) return notANumber(context); switch (_state) { case NaN: return notANumber(context); case INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case NEG_NUM: case NUM: return infinity(context); // INF - NUM = INF case INF: return notANumber(context); // INF - INF = NaN case NEG_INF: return infinity(context); // INF - (-INF) = INF default: assert(false); return 0; // should never get here } } case NEG_INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); //case taken care of above case NEG_NUM: case NUM: return negInfinity(context); // -INF - NUM = -INF case INF: return negInfinity(context); // -INF - INF = -INF case NEG_INF: return notANumber(context); // -INF - (-INF) = NaN default: assert(false); return 0; // should never get here } } case NEG_NUM: case NUM: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case INF: return negInfinity(context); // NUM - INF = -INF case NEG_INF: return infinity(context); // NUM - (-INF) = INF case NEG_NUM: case NUM: return newFloat(_float - otherImpl->_float, context); default: assert(false); return 0; // should never get here } } default: assert(false); return 0; // should never get here } } else { assert(false); // should never get here, numeric types are xs:decimal, xs:float, xs:integer and xs:double return 0; } }
/** Returns the floor of this Numeric */ Numeric::Ptr ATFloatOrDerivedImpl::floor(const DynamicContext* context) const { switch (_state) { case NaN: return notANumber(context); case INF: return infinity(context); case NEG_INF: return negInfinity(context); case NEG_NUM: case NUM: { if (isZero() && isNegative()) return negZero(context); return newFloat(_float.floor(), context); } default: { assert(false); return 0; // should never get here } } }
Numeric::Ptr ATFloatOrDerivedImpl::acos(const DynamicContext* context) const { switch (_state) { case NaN: return this; case INF: return notANumber(context); case NEG_INF: return notANumber(context); case NEG_NUM: case NUM: if(_float.abs() > 1)return notANumber(context); return newFloat(_float.acos(), context); default: assert(false); return 0; // should never get here } }
/** Rounds this Numeric to the given precision, and rounds a half to even */ Numeric::Ptr ATFloatOrDerivedImpl::roundHalfToEven(const Numeric::Ptr &precision, const DynamicContext* context) const { switch (_state) { case NaN: return notANumber(context); case INF: return infinity(context); case NEG_INF: return negInfinity(context); case NEG_NUM: case NUM: break; default: { assert(false); return 0; // should never get here } } if (isZero() && isNegative()) return this; ATFloatOrDerived::Ptr float_precision = (const Numeric::Ptr)precision->castAs(this->getPrimitiveTypeIndex(), context); MAPM exp = MAPM(10).pow(((ATFloatOrDerivedImpl*)(const ATFloatOrDerived*)float_precision)->_float); MAPM value = _float * exp; bool halfVal = false; // check if we're rounding on a half value if((value-0.5) == (value.floor())) { halfVal = true; } value = _float * exp + 0.5; value = value.floor(); // if halfVal make sure what we return has the least significant digit even if (halfVal) { if(value.is_odd()) { value = value - 1; } } value = value / exp; // the spec doesn't actually say to do this, but djf believes this is the correct way to handle rounding of -ve values which will result in 0.0E0 // if (value == 0 && isNegative()) // return negZero(context); return newFloat(value, context); }
/*Procedure that interprets current frame bytecode * Uses loop with switch statement.*/ YValue* EXECUTE_PROC(YObject* scope, YThread* th) { ExecutionFrame* frame = (ExecutionFrame*) th->frame; frame->regs[0] = (YValue*) scope; YRuntime* runtime = th->runtime; ILBytecode* bc = frame->bytecode; size_t code_len = frame->proc->code_length; while (frame->pc + 13 <= code_len) { // If runtime is paused then execution should be paused too. if (runtime->state == RuntimePaused) { th->state = ThreadPaused; while (runtime->state == RuntimePaused) YIELD(); th->state = ThreadWorking; } // Decode opcode and arguments uint8_t opcode = frame->proc->code[frame->pc]; int32_t* args = (int32_t*) &(frame->proc->code[frame->pc + 1]); const int32_t iarg0 = args[0]; const int32_t iarg1 = args[1]; const int32_t iarg2 = args[2]; // Call debugger before each instruction if nescesarry YBreakpoint breakpoint = { .procid = frame->proc->id, .pc = frame->pc }; DEBUG(th->runtime->debugger, instruction, &breakpoint, th); // Interpret opcode // See virtual machine description switch (opcode) { case VM_Halt: break; case VM_LoadConstant: { /*All constants during execution should be stored in pool. * If pool contains constant id, then constant is returned*/ YObject* cpool = th->runtime->Constants.pool; if (cpool->contains(cpool, iarg1, th)) { SET_REGISTER(cpool->get(cpool, iarg1, th), iarg0, th); break; } /*Else it is created, added to pool and returned*/ Constant* cnst = bc->getConstant(bc, iarg1); YValue* val = getNull(th); if (cnst != NULL) { switch (cnst->type) { case IntegerC: val = newInteger(cnst->value.i64, th); break; case FloatC: val = newFloat(cnst->value.fp64, th); break; case StringC: val = newString( bc->getSymbolById(bc, cnst->value.string_id), th); break; case BooleanC: val = newBoolean(cnst->value.boolean, th); break; default: break; } } cpool->put(cpool, iarg1, val, true, th); SET_REGISTER(val, iarg0, th); } break; case VM_LoadInteger: { /*Load integer from argument directly to register*/ YValue* val = newInteger(iarg1, th); SET_REGISTER(val, iarg0, th); } break; case VM_Copy: { /*Copy register value to another*/ SET_REGISTER(getRegister(iarg1, th), iarg0, th); } break; case VM_Push: { /*Push register value to stack*/ push(getRegister(iarg0, th), th); } break; case VM_PushInteger: { push(newInteger(iarg0, th), th); } break; /*Next instructions load values from two registers, * perform polymorph binary operation and * save result to third register*/ case VM_Add: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.add_operation(v1, v2, th), iarg0, th); } break; case VM_Subtract: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.subtract_operation(v1, v2, th), iarg0, th); } break; case VM_Multiply: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.multiply_operation(v1, v2, th), iarg0, th); } break; case VM_Divide: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.divide_operation(v1, v2, th), iarg0, th); } break; case VM_Modulo: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.modulo_operation(v1, v2, th), iarg0, th); } break; case VM_Power: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.power_operation(v1, v2, th), iarg0, th); } break; case VM_ShiftRight: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.shr_operation(v1, v2, th), iarg0, th); } break; case VM_ShiftLeft: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.shl_operation(v1, v2, th), iarg0, th); } break; case VM_And: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.and_operation(v1, v2, th), iarg0, th); } break; case VM_Or: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.or_operation(v1, v2, th), iarg0, th); } break; case VM_Xor: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.xor_operation(v1, v2, th), iarg0, th); } break; case VM_Compare: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(newInteger(v1->type->oper.compare(v1, v2, th), th), iarg0, th); } break; case VM_Test: { /*Take an integer from register and * check if certain bit is 1 or 0*/ YValue* arg = getRegister(iarg1, th); if (arg->type == &th->runtime->IntType) { int64_t i = ((YInteger*) arg)->value; YValue* res = newBoolean((i & iarg2) != 0, th); SET_REGISTER(res, iarg0, th); } else SET_REGISTER(getNull(th), iarg0, th); } break; case VM_FastCompare: { YValue* v1 = getRegister(iarg0, th); YValue* v2 = getRegister(iarg1, th); int i = v1->type->oper.compare(v1, v2, th); YValue* res = newBoolean((i & iarg2) != 0, th); SET_REGISTER(res, iarg0, th); } break; /*These instruction perform polymorph unary operations*/ case VM_Negate: { YValue* v1 = getRegister(iarg1, th); SET_REGISTER(v1->type->oper.negate_operation(v1, th), iarg0, th); } break; case VM_Not: { YValue* v1 = getRegister(iarg1, th); SET_REGISTER(v1->type->oper.not_operation(v1, th), iarg0, th); } break; case VM_Increment: { YValue* v1 = getRegister(iarg1, th); if (v1->type == &th->runtime->IntType) { int64_t i = getInteger(v1, th); i++; SET_REGISTER(newInteger(i, th), iarg0, th); } else if (v1->type==&th->runtime->FloatType) { double i = getFloat(v1, th); i++; SET_REGISTER(newFloat(i, th), iarg0, th); } else { SET_REGISTER(v1, iarg0, th); } } break; case VM_Decrement: { YValue* v1 = getRegister(iarg1, th); if (v1->type == &th->runtime->IntType) { int64_t i = getInteger(v1, th); i--; SET_REGISTER(newInteger(i, th), iarg0, th); } else if (v1->type==&th->runtime->FloatType) { double i = getFloat(v1, th); i--; SET_REGISTER(newFloat(i, th), iarg0, th); } else { SET_REGISTER(v1, iarg0, th); } } break; case VM_Call: { /*Invoke lambda from register. * Arguments stored in stack. * Argument count passed as argument*/ size_t argc = (size_t) popInt(th); /* YValue** args = malloc(sizeof(YValue*) * argc); for (size_t i = argc - 1; i < argc; i--) args[i] = pop(th);*/ YValue** args = &((ExecutionFrame*) th->frame)->stack[((ExecutionFrame*) th->frame)->stack_offset] - argc; ((ExecutionFrame*) th->frame)->stack_offset -= argc; YValue* val = getRegister(iarg1, th); YObject* scope = NULL; if (iarg2 != -1) { YValue* scl = getRegister(iarg2, th); if (scl->type == &th->runtime->ObjectType) scope = (YObject*) scl; else { scope = th->runtime->newObject(NULL, th); OBJECT_NEW(scope, L"value", scl, th); } } if (val->type == &th->runtime->LambdaType) { YLambda* l = (YLambda*) val; SET_REGISTER(invokeLambda(l, scope, args, argc, th), iarg0, th); } else { throwException(L"CallingNotALambda", NULL, 0, th); SET_REGISTER(getNull(th), iarg0, th); } //free(args); } break; case VM_Return: { /*Verify register value to be some type(if defined) * and return it. Execution has been ended*/ YValue* ret = getRegister(iarg0, th); if (((ExecutionFrame*) th->frame)->retType != NULL && !((ExecutionFrame*) th->frame)->retType->verify( ((ExecutionFrame*) th->frame)->retType, ret, th)) { wchar_t* wstr = toString(ret, th); throwException(L"Wrong return type", &wstr, 1, th); free(wstr); return getNull(th); } return ret; } case VM_NewObject: { /*Create object with parent(if defined)*/ YValue* p = getRegister(iarg1, th); if (iarg1 != -1 && p->type == &th->runtime->ObjectType) { YObject* obj = th->runtime->newObject((YObject*) p, th); SET_REGISTER((YValue*) obj, iarg0, th); } else SET_REGISTER((YValue*) th->runtime->newObject(NULL, th), iarg0, th); } break; case VM_NewArray: { /*Create empty array*/ SET_REGISTER((YValue*) newArray(th), iarg0, th); } break; case VM_NewLambda: { /*Create lambda. Lambda signature is stored in stack. * It is popped and formed as signature*/ // Check if lambda is vararg YValue* vmeth = pop(th); bool meth = (vmeth->type == &th->runtime->BooleanType) ? ((YBoolean*) vmeth)->value : false; YValue* vvararg = pop(th); bool vararg = (vvararg->type == &th->runtime->BooleanType) ? ((YBoolean*) vvararg)->value : false; // Get argument count and types size_t argc = (size_t) popInt(th); int32_t* argids = calloc(1, sizeof(int32_t) * argc); YoyoType** argTypes = calloc(1, sizeof(YoyoType*) * argc); for (size_t i = argc - 1; i < argc; i--) { argids[i] = (int32_t) popInt(th); YValue* val = pop(th); if (val->type == &th->runtime->DeclarationType) argTypes[i] = (YoyoType*) val; else argTypes[i] = val->type->TypeConstant; } // Get lambda return type YValue* retV = pop(th); YoyoType* retType = NULL; if (retV->type == &th->runtime->DeclarationType) retType = (YoyoType*) retV; else retType = retV->type->TypeConstant; // Get lambda scope from argument and create // lambda signature and lambda YValue* sp = getRegister(iarg2, th); if (sp->type == &th->runtime->ObjectType) { YObject* scope = (YObject*) sp; YLambda* lmbd = newProcedureLambda(iarg1, bc, scope, argids, newLambdaSignature(meth, argc, vararg, argTypes, retType, th), th); SET_REGISTER((YValue*) lmbd, iarg0, th); } else SET_REGISTER(getNull(th), iarg0, th); // Free allocated resources free(argids); free(argTypes); } break; case VM_NewOverload: { /*Pop lambdas from stack and * create overloaded lambda*/ // Pop lambda count and lambdas size_t count = (size_t) iarg1; YLambda** lambdas = malloc(sizeof(YLambda*) * count); for (size_t i = 0; i < count; i++) { YValue* val = pop(th); if (val->type == &th->runtime->LambdaType) lambdas[i] = (YLambda*) val; else lambdas[i] = NULL; } // If default lambda is defined then get it YLambda* defLmbd = NULL; if (iarg2 != -1) { YValue* val = getRegister(iarg2, th); if (val->type == &th->runtime->LambdaType) defLmbd = (YLambda*) val; } // Create overloaded lambda SET_REGISTER( (YValue*) newOverloadedLambda(lambdas, count, defLmbd, th), iarg0, th); // Free allocated resources free(lambdas); } break; case VM_NewComplexObject: { /*Pop mixin objects from stack and create complex object*/ // Get mixin count and pop mixins size_t count = (size_t) iarg2; YObject** mixins = malloc(sizeof(YObject*) * count); for (size_t i = 0; i < count; i++) { YValue* val = pop(th); if (val->type == &th->runtime->ObjectType) mixins[i] = (YObject*) val; else mixins[i] = NULL; } // Get base object YValue* basev = getRegister(iarg1, th); YObject* base = NULL; if (basev->type == &th->runtime->ObjectType) base = (YObject*) basev; else base = th->runtime->newObject(NULL, th); // Create complex object and free allocated resources SET_REGISTER((YValue*) newComplexObject(base, mixins, count, th), iarg0, th); free(mixins); } break; case VM_GetField: { /*Read value property and store it in register*/ YValue* val = getRegister(iarg1, th); if (val->type->oper.readProperty != NULL) { SET_REGISTER(val->type->oper.readProperty(iarg2, val, th), iarg0, th); } else SET_REGISTER(getNull(th), iarg0, th); } break; case VM_SetField: { /*Set objects field*/ YValue* val = getRegister(iarg0, th); if (val->type == &th->runtime->ObjectType) { YObject* obj = (YObject*) val; obj->put(obj, iarg1, getRegister(iarg2, th), false, th); } } break; case VM_NewField: { /*Create new field in object*/ YValue* val = getRegister(iarg0, th); if (val->type == &th->runtime->ObjectType) { YObject* obj = (YObject*) val; obj->put(obj, iarg1, getRegister(iarg2, th), true, th); } } break; case VM_DeleteField: { /*Delete field from object*/ YValue* val = getRegister(iarg0, th); if (val->type == &th->runtime->ObjectType) { YObject* obj = (YObject*) val; obj->remove(obj, iarg1, th); } } break; case VM_ArrayGet: { /*Get index from value. If can't then throw exception*/ YValue* val = getRegister(iarg1, th); YValue* val2 = getRegister(iarg2, th); // If value is array, but index is integer then // reads array element at index if (val->type == &th->runtime->ArrayType && val2->type == &th->runtime->IntType) { YArray* arr = (YArray*) val; size_t index = (size_t) ((YInteger*) val2)->value; SET_REGISTER(arr->get(arr, index, th), iarg0, th); } else if (val->type->oper.readIndex != NULL) { // Else calls readIndex on type(if readIndex is defined) SET_REGISTER(val->type->oper.readIndex(val, val2, th), iarg0, th); } else { throwException(L"AccesingNotAnArray", NULL, 0, th); SET_REGISTER(getNull(th), iarg0, th); } } break; case VM_ArraySet: { /*Set value to other value on index. If can't throw exception*/ YValue* val = getRegister(iarg0, th); YValue* val2 = getRegister(iarg1, th); // If value if array, but index is integer // then assigns value to an array if (val->type == &th->runtime->ArrayType && val2->type == &th->runtime->IntType) { YArray* arr = (YArray*) val; size_t index = (size_t) ((YInteger*) val2)->value; arr->set(arr, index, getRegister(iarg2, th), th); } else if (val->type->oper.readIndex != NULL) { // Else calls writeIndex on type(if writeIndex is defined) val->type->oper.writeIndex(val, val2, getRegister(iarg2, th), th); } else { throwException(L"ModifyingNotAnArray", NULL, 0, th); } } break; case VM_ArrayDelete: { /*If value is array but index is integer set array index * else throw an exception*/ YValue* val = getRegister(iarg0, th); YValue* val2 = getRegister(iarg1, th); if (val->type == &th->runtime->ArrayType && val2->type == &th->runtime->IntType) { YArray* arr = (YArray*) val; size_t index = (size_t) ((YInteger*) val2)->value; arr->remove(arr, index, th); } else if (val->type->oper.removeIndex !=NULL) { val->type->oper.removeIndex(val, val2, th); } else { throwException(L"ModifyingNotAnArray", NULL, 0, th); } } break; case VM_Goto: { /*Get label id from argument, get label address and jump*/ uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } break; case VM_GotoIfTrue: { /*Get label id from argument, get label address and jump * if condition is true*/ YValue* bln = getRegister(iarg1, th); if (bln->type == &th->runtime->BooleanType && ((YBoolean*) bln)->value) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_GotoIfFalse: { /*Get label id from argument, get label address and jump * if condition is false*/ YValue* bln = getRegister(iarg1, th); if (bln->type == &th->runtime->BooleanType && !((YBoolean*) bln)->value) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_Jump: { /*Goto to an address*/ frame->pc = iarg0; continue; } break; case VM_JumpIfTrue: { /*Goto to an address if condition is true*/ YValue* bln = getRegister(iarg1, th); if (bln->type == &th->runtime->BooleanType && ((YBoolean*) bln)->value) { frame->pc = iarg0; continue; } } break; case VM_JumpIfFalse: { /*Goto to an address if condition is false*/ YValue* bln = getRegister(iarg1, th); if (bln->type == &th->runtime->BooleanType && !((YBoolean*) bln)->value) { frame->pc = iarg0; continue; } } break; case VM_Throw: { /*Throw an exception*/ th->exception = newException(getRegister(iarg0, th), th); } break; case VM_Catch: { /*Save current exception in register and * set exception NULL*/ SET_REGISTER(th->exception, iarg0, th); th->exception = NULL; } break; case VM_OpenCatch: { /*Add next catch address to frame catch stack. * If exception is thrown then catch address being * popped from stack and interpreter * jump to it*/ CatchBlock* cb = malloc(sizeof(CatchBlock)); cb->prev = frame->catchBlock; cb->pc = iarg0; frame->catchBlock = cb; } break; case VM_CloseCatch: { /*Remove catch address from frame catch stack*/ CatchBlock* cb = frame->catchBlock; frame->catchBlock = cb->prev; free(cb); } break; case VM_Nop: { /*Does nothing*/ } break; case VM_Swap: { /*Swap two register values*/ YValue* r1 = getRegister(iarg0, th); YValue* r2 = getRegister(iarg1, th); SET_REGISTER(r1, iarg1, th); SET_REGISTER(r2, iarg0, th); } break; case VM_Subsequence: { /*Get subsequence from value if subseq method * is defined*/ YValue* reg = getRegister(iarg0, th); YValue* tfrom = getRegister(iarg1, th); YValue* tto = getRegister(iarg2, th); if (tfrom->type == &th->runtime->IntType&& tto->type == &th->runtime->IntType&& reg->type->oper.subseq!=NULL) { size_t from = (size_t) ((YInteger*) tfrom)->value; size_t to = (size_t) ((YInteger*) tto)->value; SET_REGISTER(reg->type->oper.subseq(reg, from, to, th), iarg0, th); } else SET_REGISTER(getNull(th), iarg0, th); } break; case VM_Iterator: { /*Get iterator from value if it is iterable*/ YValue* v = getRegister(iarg1, th); if (v->type->oper.iterator != NULL) { SET_REGISTER((YValue*) v->type->oper.iterator(v, th), iarg0, th);\ } else { SET_REGISTER(getNull(th), iarg0, th); } } break; case VM_Iterate: { /*If iterator has next value than get it and save * to register. If iterator doesn't has next value * then jump to a label*/ YValue* v = getRegister(iarg1, th); YValue* value = NULL; if (v->type->oper.iterator != NULL) { YoyoIterator* iter = v->type->oper.iterator(v, th); if (iter->hasNext(iter, th)) value = iter->next(iter, th); } if (value == NULL) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg2)->value; frame->pc = addr; } else SET_REGISTER(value, iarg0, th); } break; case VM_NewInterface: { /*Build new interface*/ YoyoAttribute* attrs = calloc(1, sizeof(YoyoAttribute) * iarg2); // Pop interface parents YoyoInterface** parents = calloc(1, sizeof(YoyoInterface*) * iarg1); for (int32_t i = 0; i < iarg1; i++) { YValue* val = pop(th); YoyoType* type = NULL; if (val->type == &th->runtime->DeclarationType) type = (YoyoType*) val; else type = val->type->TypeConstant; parents[i] = type->type == InterfaceDT ? (YoyoInterface*) type : NULL; } // Pop interface fields for (int32_t i = 0; i < iarg2; i++) { attrs[i].id = popInt(th); YValue* val = pop(th); YoyoType* type = NULL; if (val->type == &th->runtime->DeclarationType) type = (YoyoType*) val; else type = val->type->TypeConstant; attrs[i].type = type; } // Build interface and free allocated resources SET_REGISTER( (YValue*) newInterface(parents, (size_t) iarg1, attrs, (size_t) iarg2, th), iarg0, th); free(attrs); free(parents); } break; case VM_ChangeType: { /*Change field type*/ YValue* val = getRegister(iarg2, th); YoyoType* type = NULL; if (val->type == &th->runtime->DeclarationType) type = (YoyoType*) val; else type = val->type->TypeConstant; YValue* o = getRegister(iarg0, th); if (o->type == &th->runtime->ObjectType) { YObject* obj = (YObject*) o; obj->setType(obj, iarg1, type, th); } } break; case VM_GotoIfEquals: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_EQUALS) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfEquals: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_EQUALS) != 0) { frame->pc = iarg0; continue; } } break; case VM_GotoIfNotEquals: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_NOT_EQUALS) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfNotEquals: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_NOT_EQUALS) != 0) { frame->pc = iarg0; continue; } } break; case VM_GotoIfGreater: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_GREATER) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfGreater: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_GREATER) != 0) { frame->pc = iarg0; continue; } } break; case VM_GotoIfLesser: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_LESSER) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfLesser: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_LESSER) != 0) { frame->pc = iarg0; continue; } } break; case VM_GotoIfNotLesser: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_GREATER_OR_EQUALS) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfNotLesser: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_GREATER_OR_EQUALS) != 0) { frame->pc = iarg0; continue; } } break; case VM_GotoIfNotGreater: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_LESSER_OR_EQUALS) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfNotGreater: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_LESSER_OR_EQUALS) != 0) { frame->pc = iarg0; continue; } } break; case VM_CheckType: { YValue* value = getRegister(iarg0, th); YValue* tv = getRegister(iarg1, th); YoyoType* type = NULL; if (tv->type == &th->runtime->DeclarationType) type = (YoyoType*) tv; else type = tv->type->TypeConstant; if (!type->verify(type, value, th)) { wchar_t* wcs = getSymbolById(&th->runtime->symbols, iarg2); throwException(L"WrongFieldType", &wcs, 1, th); } } break; } /*If there is an exception then get last catch block * and jump to an address. If catch stack is empty * then return from procedure*/ if (th->exception != NULL) { if (frame->catchBlock != NULL) { frame->pc = frame->proc->getLabel(frame->proc, frame->catchBlock->pc)->value; continue; } else return getNull(th); } frame->pc += 13; } return getNull(th); }
Numeric::Ptr ATFloatOrDerivedImpl::power(const Numeric::Ptr &other, const DynamicContext* context) const { switch(other->getPrimitiveTypeIndex()) { case DECIMAL: // if other is a decimal, promote it to xs:float return power(context->getItemFactory()->createFloat(other->asMAPM(), context), context); case FLOAT: { ATFloatOrDerivedImpl *otherImpl = (ATFloatOrDerivedImpl*)other.get(); switch(_state) { case NaN: return this; case INF: { switch(otherImpl->_state) { case NaN: return other; case NEG_NUM: case NUM: case INF: case NEG_INF: return this; default: assert(false); return 0; // should never get here } } case NEG_INF: { switch(otherImpl->_state) { case NaN: return other; case NEG_NUM: case NUM: case INF: case NEG_INF: return this; default: assert(false); return 0; // should never get here } } case NEG_NUM: case NUM: { switch(otherImpl->_state) { case NaN: return other; case INF: return other; case NEG_INF: return infinity(context); case NEG_NUM: case NUM: return newFloat(_float.pow(otherImpl->_float), context); default: assert(false); return 0; // should never get here } } default: assert(false); return 0; // should never get here } } case DOUBLE: return ((Numeric*)this->castAs(DOUBLE, context).get())->power(other, context); default: assert(false); return 0; // Shouldn't happen } }
/** Returns a Numeric object which is the quotient of this and other */ Numeric::Ptr ATFloatOrDerivedImpl::divide(const Numeric::Ptr &other, const DynamicContext* context) const { if(other->getPrimitiveTypeIndex() == AnyAtomicType::DECIMAL) { // if other is a decimal, promote it to xs:float return this->divide((const Numeric::Ptr )other->castAs(this->getPrimitiveTypeIndex(), context), context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::DOUBLE) { // if other is a double, promote this to xs:double return ((const Numeric::Ptr )this->castAs(other->getPrimitiveTypeIndex(), context))->divide(other, context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::FLOAT) { // same primitive type, can make comparison ATFloatOrDerivedImpl* otherImpl = (ATFloatOrDerivedImpl*)(const Numeric*)other; if(otherImpl->_state == NaN) return notANumber(context); switch (_state) { case NaN: return notANumber(context); case INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case NEG_NUM: case NUM: return other->isPositive() ? infinity(context) : negInfinity(context); // INF / NUM = +/-INF case INF: return notANumber(context); // INF / INF = NaN case NEG_INF: return notANumber(context); // INF / (-INF) = NaN default: assert(false); return 0; // should never get here } // switch }// case case NEG_INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); //case taken care of above case NEG_NUM: case NUM: return other->isPositive() ? negInfinity(context) : infinity(context); // -INF / NUM = -INF case INF: return notANumber(context); // -INF / INF = NaN case NEG_INF: return notANumber(context); // -INF / (-INF) = NaN default: assert(false); return 0; // should never get here } // switch } // case case NEG_NUM: case NUM: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case INF: { // NUM / INF = +/-0 if(this->isNegative()) { return negZero(context); } else { return newFloat(0, context); } }// case case NEG_INF: { // NUM / -INF = +/-0 if(this->isPositive()) { return negZero(context); } else { return newFloat(0, context); } }// case case NEG_NUM: case NUM: { if(other->isZero()) { if(this->isZero()) return notANumber(context); if((this->isNegative() && other->isPositive()) || (this->isPositive() && other->isNegative())) { return negInfinity(context); // NUM / (-0) or (-NUM) / 0 = -INF } else { return infinity(context); // NUM / 0 or (-NUM) / (-0) = INF } } else if(this->isZero()) { if((this->isNegative() && other->isPositive()) || (this->isPositive() && other->isNegative())) { return negZero(context); // 0 / (-NUM) or (-0) / NUM = -0 } else { return newFloat(0, context); // 0 / NUM or (-0) / (-NUM) = 0 } } return newFloat(_float / otherImpl->_float, context); }// case default: assert(false); return 0; // should never get here }// switch }// case default: assert(false); return 0; // should never get here }// switch } else { assert(false); // should never get here, numeric types are xs:decimal, xs:float, xs:integer and xs:double return 0; } }
/** Returns a Numeric object which is the sum of this and other */ Numeric::Ptr ATFloatOrDerivedImpl::add(const Numeric::Ptr &other, const DynamicContext* context) const { if(other->getPrimitiveTypeIndex() == AnyAtomicType::DECIMAL) { // if other is a decimal, promote it to xs:float return this->add((const Numeric::Ptr )other->castAs(this->getPrimitiveTypeIndex(), context), context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::DOUBLE) { // if other is a double, promote this to xs:double return ((const Numeric::Ptr )this->castAs(other->getPrimitiveTypeIndex(), context))->add(other, context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::FLOAT) { // same primitive type, can make comparison ATFloatOrDerivedImpl* otherImpl = (ATFloatOrDerivedImpl*)(const Numeric*)other; if(otherImpl->_state == NaN) return notANumber(context); switch (_state) { case NaN: return notANumber(context); case INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case NEG_NUM: case NUM: return infinity(context); // INF + NUM = INF case INF: return infinity(context); // INF + INF = INF case NEG_INF: return notANumber(context); // INF + (-INF) = NaN default: assert(false); return 0; // should never get here } } case NEG_INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); //case taken care of above case NEG_NUM: case NUM: return negInfinity(context); // -INF + NUM = -INF case INF: return notANumber(context); // -INF + INF = NaN case NEG_INF: return negInfinity(context); // -INF + (-INF) = -INF default: assert(false); return 0; // should never get here } } case NEG_NUM: case NUM: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case INF: return infinity(context); case NEG_INF: return negInfinity(context); case NEG_NUM: case NUM: { // Handle positive and negative zero if(_float.sign()==0 && otherImpl->_float!=0) return other; else if(_float.sign()!=0 && otherImpl->_float==0) return this; else if(_float.sign()==0 && otherImpl->_float==0) { if(_state==otherImpl->_state) // sum of two zero of the same sign -> result is equal to any of the two items return this; else // sum of two zero of different sign -> result is equal to +0 return newFloat(0, context); } return newFloat(_float + otherImpl->_float, context); } default: assert(false); return 0; // should never get here } } default: assert(false); return 0; // should never get here } } else { assert(false); // should never get here, numeric types are xs:decimal, xs:float, xs:integer and xs:double return 0; } }