static EjsVar *coerceVoidOperands(Ejs *ejs, EjsVoid *lhs, int opcode, EjsVoid *rhs) { switch (opcode) { case EJS_OP_ADD: if (!ejsIsNumber(rhs)) { return ejsInvokeOperator(ejs, (EjsVar*) ejsToString(ejs, lhs), opcode, rhs); } /* Fall through */ case EJS_OP_AND: case EJS_OP_DIV: case EJS_OP_MUL: case EJS_OP_OR: case EJS_OP_REM: case EJS_OP_SHL: case EJS_OP_SHR: case EJS_OP_SUB: case EJS_OP_USHR: case EJS_OP_XOR: return ejsInvokeOperator(ejs, (EjsVar*) ejs->nanValue, opcode, rhs); /* * Comparision */ case EJS_OP_COMPARE_LE: case EJS_OP_COMPARE_LT: case EJS_OP_COMPARE_GE: case EJS_OP_COMPARE_GT: return (EjsVar*) ejs->falseValue; case EJS_OP_COMPARE_NE: case EJS_OP_COMPARE_STRICTLY_NE: if (ejsIsNull(rhs)) { return (EjsVar*) ejs->falseValue; } return (EjsVar*) ejs->trueValue; case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_STRICTLY_EQ: if (ejsIsNull(rhs)) { return (EjsVar*) ejs->trueValue; } return (EjsVar*) ejs->falseValue; /* * Unary operators */ case EJS_OP_LOGICAL_NOT: case EJS_OP_NOT: case EJS_OP_NEG: return 0; case EJS_OP_COMPARE_UNDEFINED: case EJS_OP_COMPARE_NOT_ZERO: case EJS_OP_COMPARE_NULL: return (EjsVar*) ejs->trueValue; case EJS_OP_COMPARE_FALSE: case EJS_OP_COMPARE_TRUE: case EJS_OP_COMPARE_ZERO: return (EjsVar*) ejs->falseValue; default: ejsThrowTypeError(ejs, "Opcode %d not valid for type %s", opcode, lhs->type->qname.name); return ejs->undefinedValue; } return 0; }
/* * Coerce operands for invokeOperator */ static EjsVar *coerceBooleanOperands(Ejs *ejs, EjsVar *lhs, int opcode, EjsVar *rhs) { switch (opcode) { case EJS_OP_ADD: if (ejsIsUndefined(rhs)) { return (EjsVar*) ejs->nanValue; } else if (ejsIsNull(rhs) || ejsIsNumber(rhs) || ejsIsDate(rhs)) { return ejsInvokeOperator(ejs, (EjsVar*) ejsToNumber(ejs, lhs), opcode, rhs); } else { return ejsInvokeOperator(ejs, (EjsVar*) ejsToString(ejs, lhs), opcode, rhs); } break; case EJS_OP_AND: case EJS_OP_DIV: case EJS_OP_MUL: case EJS_OP_OR: case EJS_OP_REM: case EJS_OP_SHL: case EJS_OP_SHR: case EJS_OP_SUB: case EJS_OP_USHR: case EJS_OP_XOR: return ejsInvokeOperator(ejs, (EjsVar*) ejsToNumber(ejs, lhs), opcode, rhs); case EJS_OP_COMPARE_LE: case EJS_OP_COMPARE_LT: case EJS_OP_COMPARE_GE: case EJS_OP_COMPARE_GT: case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_NE: if (ejsIsString(rhs)) { return ejsInvokeOperator(ejs, (EjsVar*) ejsToString(ejs, lhs), opcode, rhs); } return ejsInvokeOperator(ejs, (EjsVar*) ejsToNumber(ejs, lhs), opcode, rhs); case EJS_OP_COMPARE_STRICTLY_NE: return (EjsVar*) ejs->trueValue; case EJS_OP_COMPARE_STRICTLY_EQ: return (EjsVar*) ejs->falseValue; /* * Unary operators */ case EJS_OP_LOGICAL_NOT: case EJS_OP_NOT: case EJS_OP_NEG: return 0; case EJS_OP_COMPARE_NOT_ZERO: case EJS_OP_COMPARE_TRUE: return (EjsVar*) (((EjsBoolean*) lhs)->value ? ejs->trueValue: ejs->falseValue); case EJS_OP_COMPARE_ZERO: case EJS_OP_COMPARE_FALSE: return (EjsVar*) (((EjsBoolean*) lhs)->value ? ejs->falseValue : ejs->trueValue); case EJS_OP_COMPARE_UNDEFINED: case EJS_OP_COMPARE_NULL: return (EjsVar*) ejs->falseValue; default: ejsThrowTypeError(ejs, "Opcode %d not valid for type %s", opcode, lhs->type->qname.name); return ejs->undefinedValue; } }
static EjsAny *coerceUriOperands(Ejs *ejs, EjsUri *lhs, int opcode, EjsAny *rhs) { HttpUri *uri; char *ustr; switch (opcode) { /* Binary operators */ case EJS_OP_ADD: uri = lhs->uri; ustr = httpFormatUri(uri->scheme, uri->host, uri->port, uri->path, uri->reference, uri->query, 0); return ejsInvokeOperator(ejs, ejsCreateStringFromAsc(ejs, ustr), opcode, rhs); case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_NE: case EJS_OP_COMPARE_LE: case EJS_OP_COMPARE_LT: case EJS_OP_COMPARE_GE: case EJS_OP_COMPARE_GT: if (!ejsIsDefined(ejs, rhs)) { return ((opcode == EJS_OP_COMPARE_EQ) ? ESV(false): ESV(true)); } uri = lhs->uri; ustr = httpFormatUri(uri->scheme, uri->host, uri->port, uri->path, uri->reference, uri->query, 0); return ejsInvokeOperator(ejs, ejsCreateStringFromAsc(ejs, ustr), opcode, rhs); case EJS_OP_COMPARE_STRICTLY_NE: return ESV(true); case EJS_OP_COMPARE_STRICTLY_EQ: return ESV(false); case EJS_OP_COMPARE_NOT_ZERO: case EJS_OP_COMPARE_TRUE: return ESV(true); case EJS_OP_COMPARE_ZERO: case EJS_OP_COMPARE_FALSE: return ESV(false); case EJS_OP_COMPARE_UNDEFINED: case EJS_OP_COMPARE_NULL: return ESV(false); default: ejsThrowTypeError(ejs, "Opcode %d not valid for type %@", opcode, TYPE(lhs)->qname.name); return ESV(undefined); } return 0; }
/* Handle all core operators. We currenly handle only === and !== TODO. Must implement: +, -, <, >, <=, >=, ==, ===, !=, !==, &, | */ static EjsObj *invokeOperator(Ejs *ejs, EjsXML *lhs, int opCode, EjsXML *rhs) { EjsObj *l, *r; bool boolResult; assure(ejsIsXML(ejs, lhs)); assure(ejsIsXML(ejs, rhs)); // TODO - Complete switch (opCode) { case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_STRICTLY_EQ: boolResult = (lhs == rhs); break; case EJS_OP_COMPARE_NE: case EJS_OP_COMPARE_STRICTLY_NE: boolResult = !(lhs == rhs); break; default: /* Cast to strings and re-invoke */ l = ejsCast(ejs, lhs, String); r = ejsCast(ejs, rhs, String); return ejsInvokeOperator(ejs, l, opCode, r); } return (EjsObj*) ejsCreateBoolean(ejs, boolResult); }
static EjsAny *invokeNullOperator(Ejs *ejs, EjsObj *lhs, int opcode, EjsObj *rhs) { EjsObj *result; if (rhs == 0 || TYPE(lhs) != TYPE(rhs)) { if ((result = coerceNullOperands(ejs, lhs, opcode, rhs)) != 0) { return result; } } /* Types now match. Both left and right types are both "null" */ switch (opcode) { /* NOTE: strict eq is the same as eq */ case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_STRICTLY_EQ: case EJS_OP_COMPARE_LE: case EJS_OP_COMPARE_GE: case EJS_OP_COMPARE_UNDEFINED: case EJS_OP_COMPARE_NOT_ZERO: case EJS_OP_COMPARE_NULL: return ESV(true); case EJS_OP_COMPARE_NE: case EJS_OP_COMPARE_STRICTLY_NE: case EJS_OP_COMPARE_LT: case EJS_OP_COMPARE_GT: case EJS_OP_COMPARE_FALSE: case EJS_OP_COMPARE_TRUE: case EJS_OP_COMPARE_ZERO: return ESV(false); /* Unary operators */ case EJS_OP_LOGICAL_NOT: case EJS_OP_NOT: case EJS_OP_NEG: return ESV(one); /* Binary operators. Reinvoke with left = zero */ case EJS_OP_ADD: case EJS_OP_AND: case EJS_OP_DIV: case EJS_OP_MUL: case EJS_OP_OR: case EJS_OP_REM: case EJS_OP_SHL: case EJS_OP_SHR: case EJS_OP_SUB: case EJS_OP_USHR: case EJS_OP_XOR: return ejsInvokeOperator(ejs, ESV(zero), opcode, rhs); default: ejsThrowTypeError(ejs, "Opcode %d not implemented for type %@", opcode, TYPE(lhs)->qname.name); return 0; } }
/* Cast operands as required for invokeArrayOperator */ static EjsObj *coerceArrayOperands(Ejs *ejs, EjsObj *lhs, int opcode, EjsObj *rhs) { switch (opcode) { /* Binary operators */ case EJS_OP_ADD: return ejsInvokeOperator(ejs, arrayToString(ejs, (EjsArray*) lhs, 0, 0), opcode, rhs); case EJS_OP_AND: case EJS_OP_DIV: case EJS_OP_MUL: case EJS_OP_OR: case EJS_OP_REM: case EJS_OP_SHL: case EJS_OP_SHR: case EJS_OP_SUB: case EJS_OP_USHR: case EJS_OP_XOR: return ejsInvokeOperator(ejs, ESV(zero), opcode, rhs); case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_NE: if (!ejsIsDefined(ejs, rhs)) { return ((opcode == EJS_OP_COMPARE_EQ) ? ESV(false): ESV(true)); } else if (ejsIs(ejs, rhs, Number)) { return ejsInvokeOperator(ejs, ejsToNumber(ejs, lhs), opcode, rhs); } return ejsInvokeOperator(ejs, ejsToString(ejs, lhs), opcode, rhs); case EJS_OP_COMPARE_LE: case EJS_OP_COMPARE_LT: case EJS_OP_COMPARE_GE: case EJS_OP_COMPARE_GT: if (ejsIs(ejs, rhs, Number)) { return ejsInvokeOperator(ejs, ejsToNumber(ejs, lhs), opcode, rhs); } return ejsInvokeOperator(ejs, ejsToString(ejs, lhs), opcode, rhs); case EJS_OP_COMPARE_STRICTLY_NE: case EJS_OP_COMPARE_UNDEFINED: case EJS_OP_COMPARE_NOT_ZERO: case EJS_OP_COMPARE_NULL: return ESV(true); case EJS_OP_COMPARE_STRICTLY_EQ: case EJS_OP_COMPARE_FALSE: case EJS_OP_COMPARE_TRUE: case EJS_OP_COMPARE_ZERO: return ESV(false); /* Unary operators */ case EJS_OP_LOGICAL_NOT: case EJS_OP_NOT: case EJS_OP_NEG: return 0; default: ejsThrowTypeError(ejs, "Opcode %d not valid for type %@", opcode, TYPE(lhs)->qname.name); return ESV(undefined); } }
static EjsAny *coerceNullOperands(Ejs *ejs, EjsObj *lhs, int opcode, EjsObj *rhs) { switch (opcode) { case EJS_OP_ADD: if (!ejsIs(ejs, rhs, Number)) { return ejsInvokeOperator(ejs, ejsToString(ejs, lhs), opcode, rhs); } /* Fall through */ case EJS_OP_AND: case EJS_OP_DIV: case EJS_OP_MUL: case EJS_OP_OR: case EJS_OP_REM: case EJS_OP_SHL: case EJS_OP_SHR: case EJS_OP_SUB: case EJS_OP_USHR: case EJS_OP_XOR: return ejsInvokeOperator(ejs, ESV(zero), opcode, rhs); /* Comparision */ case EJS_OP_COMPARE_LE: case EJS_OP_COMPARE_LT: case EJS_OP_COMPARE_GE: case EJS_OP_COMPARE_GT: if (ejsIs(ejs, rhs, Number)) { return ejsInvokeOperator(ejs, ESV(zero), opcode, rhs); } else if (ejsIs(ejs, rhs, String)) { return ejsInvokeOperator(ejs, ejsToString(ejs, lhs), opcode, rhs); } break; case EJS_OP_COMPARE_NE: if (ejsIs(ejs, rhs, Void)) { return ESV(false); } return ESV(true); case EJS_OP_COMPARE_STRICTLY_NE: return ESV(true); case EJS_OP_COMPARE_EQ: if (ejsIs(ejs, rhs, Void)) { return ESV(true); } return ESV(false); case EJS_OP_COMPARE_STRICTLY_EQ: return ESV(false); case EJS_OP_COMPARE_UNDEFINED: case EJS_OP_COMPARE_NOT_ZERO: case EJS_OP_COMPARE_NULL: return ESV(true); case EJS_OP_COMPARE_FALSE: case EJS_OP_COMPARE_TRUE: case EJS_OP_COMPARE_ZERO: return ESV(false); /* Unary operators */ case EJS_OP_LOGICAL_NOT: case EJS_OP_NOT: case EJS_OP_NEG: return 0; default: ejsThrowTypeError(ejs, "Opcode %d not valid for type %@", opcode, TYPE(lhs)->qname.name); return ESV(undefined); } return 0; }