зеркало из https://github.com/mozilla/pjs.git
ECMA3 semantics for toPrimitive.
This commit is contained in:
Родитель
b2486b2092
Коммит
736c95e712
|
@ -77,7 +77,9 @@ namespace MetaData {
|
|||
|
||||
static js2val Boolean_toString(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
|
||||
{
|
||||
if (meta->objectType(thisValue) != meta->booleanClass)
|
||||
if (!JS2VAL_IS_OBJECT(thisValue)
|
||||
|| (JS2VAL_TO_OBJECT(thisValue)->kind != PrototypeInstanceKind)
|
||||
|| ((checked_cast<PrototypeInstance *>(JS2VAL_TO_OBJECT(thisValue)))->type != meta->booleanClass))
|
||||
meta->reportError(Exception::typeError, "Boolean.toString called on something other than a boolean thing", meta->engine->errorPos());
|
||||
BooleanInstance *boolInst = checked_cast<BooleanInstance *>(JS2VAL_TO_OBJECT(thisValue));
|
||||
return (boolInst->mValue) ? meta->engine->allocString(meta->engine->true_StringAtom) : meta->engine->allocString(meta->engine->false_StringAtom);
|
||||
|
@ -85,7 +87,9 @@ namespace MetaData {
|
|||
|
||||
static js2val Boolean_valueOf(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
|
||||
{
|
||||
if (meta->objectType(thisValue) != meta->booleanClass)
|
||||
if (!JS2VAL_IS_OBJECT(thisValue)
|
||||
|| (JS2VAL_TO_OBJECT(thisValue)->kind != PrototypeInstanceKind)
|
||||
|| ((checked_cast<PrototypeInstance *>(JS2VAL_TO_OBJECT(thisValue)))->type != meta->booleanClass))
|
||||
meta->reportError(Exception::typeError, "Boolean.valueOf called on something other than a boolean thing", meta->engine->errorPos());
|
||||
BooleanInstance *boolInst = checked_cast<BooleanInstance *>(JS2VAL_TO_OBJECT(thisValue));
|
||||
return (boolInst->mValue) ? JS2VAL_TRUE : JS2VAL_FALSE;
|
||||
|
|
|
@ -378,6 +378,7 @@ namespace MetaData {
|
|||
INIT_STRINGATOM(prototype),
|
||||
INIT_STRINGATOM(length),
|
||||
INIT_STRINGATOM(toString),
|
||||
INIT_STRINGATOM(valueOf),
|
||||
traceInstructions(false)
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
|
@ -847,6 +848,7 @@ namespace MetaData {
|
|||
JS2Object::mark(prototype_StringAtom);
|
||||
JS2Object::mark(length_StringAtom);
|
||||
JS2Object::mark(toString_StringAtom);
|
||||
JS2Object::mark(valueOf_StringAtom);
|
||||
}
|
||||
|
||||
void JS2Engine::pushHandler(uint8 *pc)
|
||||
|
|
|
@ -240,6 +240,7 @@ public:
|
|||
const String *prototype_StringAtom;
|
||||
const String *length_StringAtom;
|
||||
const String *toString_StringAtom;
|
||||
const String *valueOf_StringAtom;
|
||||
|
||||
// The activation stack, when it's empty and a return is executed, the
|
||||
// interpreter quits
|
||||
|
|
|
@ -4061,43 +4061,75 @@ deleteClassProperty:
|
|||
}
|
||||
if (JS2VAL_IS_DOUBLE(x))
|
||||
return engine->numberToString(JS2VAL_TO_DOUBLE(x));
|
||||
return toString(toPrimitive(x));
|
||||
return toString(toPrimitive(x, StringHint));
|
||||
}
|
||||
|
||||
// Invoke the named function on the thisValue object (it is an object)
|
||||
// Returns false if no callable function exists. Otherwise return the
|
||||
// function result value.
|
||||
bool JS2Metadata::invokeFunctionOnObject(js2val thisValue, const String *fnName, js2val &result)
|
||||
{
|
||||
Multiname mn(engine->toString_StringAtom, publicNamespace);
|
||||
LookupKind lookup(false, JS2VAL_NULL);
|
||||
js2val fnVal;
|
||||
|
||||
if (readProperty(thisValue, &mn, &lookup, RunPhase, &fnVal)) {
|
||||
if (JS2VAL_IS_OBJECT(fnVal)) {
|
||||
JS2Object *fnObj = JS2VAL_TO_OBJECT(fnVal);
|
||||
if ((fnObj->kind == CallableInstanceKind) && (objectType(fnVal) == functionClass)) {
|
||||
FunctionWrapper *fWrap = (checked_cast<CallableInstance *>(fnObj))->fWrap;
|
||||
if (fWrap->code) {
|
||||
result = (fWrap->code)(this, thisValue, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else // XXX here we accept the bound this, can that be right?
|
||||
if (fnObj->kind == MethodClosureKind) {
|
||||
MethodClosure *mc = checked_cast<MethodClosure *>(fnObj);
|
||||
CallableInstance *fInst = mc->method->fInst;
|
||||
FunctionWrapper *fWrap = fInst->fWrap;
|
||||
if (fWrap->code) {
|
||||
result = (fWrap->code)(this, mc->thisObject, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// x is not a primitive (it is an object and not null)
|
||||
js2val JS2Metadata::convertValueToPrimitive(js2val x)
|
||||
js2val JS2Metadata::convertValueToPrimitive(js2val x, Hint hint)
|
||||
{
|
||||
// return [[DefaultValue]] --> get property 'toString' and invoke it,
|
||||
// if not available or result is not primitive then try property 'valueOf'
|
||||
// if that's not available or returns a non primitive, throw a TypeError
|
||||
|
||||
Multiname mn(engine->toString_StringAtom, publicNamespace);
|
||||
LookupKind lookup(false, JS2VAL_NULL);
|
||||
js2val result;
|
||||
if (readProperty(x, &mn, &lookup, RunPhase, &result)) {
|
||||
if (JS2VAL_IS_OBJECT(result)) {
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(result);
|
||||
if ((obj->kind == CallableInstanceKind) && (objectType(result) == functionClass)) {
|
||||
FunctionWrapper *fWrap = (checked_cast<CallableInstance *>(obj))->fWrap;
|
||||
if (fWrap->code) {
|
||||
result = (fWrap->code)(this, result, NULL, 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (obj->kind == MethodClosureKind) {
|
||||
MethodClosure *mc = checked_cast<MethodClosure *>(obj);
|
||||
CallableInstance *fInst = mc->method->fInst;
|
||||
FunctionWrapper *fWrap = fInst->fWrap;
|
||||
if (fWrap->code) {
|
||||
result = (fWrap->code)(this, mc->thisObject, NULL, 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (hint == StringHint) {
|
||||
js2val result;
|
||||
if (invokeFunctionOnObject(x, engine->toString_StringAtom, result)) {
|
||||
if (JS2VAL_IS_PRIMITIVE(result))
|
||||
return result;
|
||||
}
|
||||
if (invokeFunctionOnObject(x, engine->valueOf_StringAtom, result)) {
|
||||
if (JS2VAL_IS_PRIMITIVE(result))
|
||||
return result;
|
||||
}
|
||||
reportError(Exception::typeError, "DefaultValue failure", engine->errorPos());
|
||||
}
|
||||
|
||||
return STRING_TO_JS2VAL(engine->object_StringAtom);
|
||||
else {
|
||||
js2val result;
|
||||
if (invokeFunctionOnObject(x, engine->valueOf_StringAtom, result)) {
|
||||
if (JS2VAL_IS_PRIMITIVE(result))
|
||||
return result;
|
||||
}
|
||||
if (invokeFunctionOnObject(x, engine->toString_StringAtom, result)) {
|
||||
if (JS2VAL_IS_PRIMITIVE(result))
|
||||
return result;
|
||||
}
|
||||
reportError(Exception::typeError, "DefaultValue failure", engine->errorPos());
|
||||
}
|
||||
return JS2VAL_VOID;
|
||||
}
|
||||
|
||||
// x is not a number
|
||||
|
@ -4118,7 +4150,7 @@ deleteClassProperty:
|
|||
reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos());
|
||||
if (JS2VAL_IS_UNINITIALIZED(x))
|
||||
reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos());
|
||||
return toFloat64(toPrimitive(x));
|
||||
return toFloat64(toPrimitive(x, NumberHint));
|
||||
}
|
||||
|
||||
// x is not a number, convert it to one
|
||||
|
|
|
@ -112,6 +112,7 @@ enum ObjectKind {
|
|||
|
||||
enum Plurality { Singular, Plural };
|
||||
|
||||
enum Hint { NoHint, NumberHint, StringHint };
|
||||
|
||||
class PondScum {
|
||||
public:
|
||||
|
@ -1051,6 +1052,7 @@ public:
|
|||
JS2Class *getVariableType(Variable *v, Phase phase, size_t pos);
|
||||
|
||||
js2val invokeFunction(const char *fname);
|
||||
bool invokeFunctionOnObject(js2val thisValue, const String *fnName, js2val &result);
|
||||
|
||||
bool readProperty(js2val container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval);
|
||||
bool readProperty(Frame *pf, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval);
|
||||
|
@ -1079,7 +1081,7 @@ public:
|
|||
void reportError(Exception::Kind kind, const char *message, size_t pos, const String *name);
|
||||
|
||||
const String *convertValueToString(js2val x);
|
||||
js2val convertValueToPrimitive(js2val x);
|
||||
js2val convertValueToPrimitive(js2val x, Hint hint);
|
||||
float64 convertValueToDouble(js2val x);
|
||||
bool convertValueToBoolean(js2val x);
|
||||
int32 convertValueToInteger(js2val x);
|
||||
|
@ -1087,7 +1089,7 @@ public:
|
|||
js2val convertValueToObject(js2val x);
|
||||
|
||||
const String *toString(js2val x) { if (JS2VAL_IS_STRING(x)) return JS2VAL_TO_STRING(x); else return convertValueToString(x); }
|
||||
js2val toPrimitive(js2val x) { if (JS2VAL_IS_PRIMITIVE(x)) return x; else return convertValueToPrimitive(x); }
|
||||
js2val toPrimitive(js2val x, Hint hint) { if (JS2VAL_IS_PRIMITIVE(x)) return x; else return convertValueToPrimitive(x, hint); }
|
||||
float64 toFloat64(js2val x);
|
||||
js2val toGeneralNumber(js2val x) { if (JS2VAL_IS_NUMBER(x)) return x; else return convertValueToGeneralNumber(x); }
|
||||
bool toBoolean(js2val x) { if (JS2VAL_IS_BOOLEAN(x)) return JS2VAL_TO_BOOLEAN(x); else return convertValueToBoolean(x); }
|
||||
|
|
|
@ -329,8 +329,8 @@
|
|||
{
|
||||
b = pop();
|
||||
a = pop();
|
||||
a = meta->toPrimitive(a);
|
||||
b = meta->toPrimitive(b);
|
||||
a = meta->toPrimitive(a, NumberHint);
|
||||
b = meta->toPrimitive(b, NumberHint);
|
||||
if (JS2VAL_IS_STRING(a) || JS2VAL_IS_STRING(b)) {
|
||||
const String *astr = meta->toString(a);
|
||||
const String *bstr = meta->toString(b);
|
||||
|
@ -692,8 +692,8 @@
|
|||
{
|
||||
b = pop();
|
||||
a = pop();
|
||||
a = meta->toPrimitive(a);
|
||||
b = meta->toPrimitive(b);
|
||||
a = meta->toPrimitive(a, NumberHint);
|
||||
b = meta->toPrimitive(b, NumberHint);
|
||||
bool rval;
|
||||
if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b))
|
||||
rval = (*JS2VAL_TO_STRING(a) < *JS2VAL_TO_STRING(b));
|
||||
|
@ -707,8 +707,8 @@
|
|||
{
|
||||
b = pop();
|
||||
a = pop();
|
||||
a = meta->toPrimitive(a);
|
||||
b = meta->toPrimitive(b);
|
||||
a = meta->toPrimitive(a, NumberHint);
|
||||
b = meta->toPrimitive(b, NumberHint);
|
||||
bool rval;
|
||||
if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b))
|
||||
rval = (*JS2VAL_TO_STRING(a) <= *JS2VAL_TO_STRING(b));
|
||||
|
@ -722,8 +722,8 @@
|
|||
{
|
||||
b = pop();
|
||||
a = pop();
|
||||
a = meta->toPrimitive(a);
|
||||
b = meta->toPrimitive(b);
|
||||
a = meta->toPrimitive(a, NumberHint);
|
||||
b = meta->toPrimitive(b, NumberHint);
|
||||
bool rval;
|
||||
if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b))
|
||||
rval = (*JS2VAL_TO_STRING(a) > *JS2VAL_TO_STRING(b));
|
||||
|
@ -737,8 +737,8 @@
|
|||
{
|
||||
b = pop();
|
||||
a = pop();
|
||||
a = meta->toPrimitive(a);
|
||||
b = meta->toPrimitive(b);
|
||||
a = meta->toPrimitive(a, NumberHint);
|
||||
b = meta->toPrimitive(b, NumberHint);
|
||||
bool rval;
|
||||
if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b))
|
||||
rval = (*JS2VAL_TO_STRING(a) >= *JS2VAL_TO_STRING(b));
|
||||
|
@ -761,7 +761,7 @@
|
|||
if (JS2VAL_IS_BOOLEAN(b))
|
||||
rval = (JS2VAL_TO_BOOLEAN(a) == JS2VAL_TO_BOOLEAN(b));
|
||||
else {
|
||||
b = meta->toPrimitive(b);
|
||||
b = meta->toPrimitive(b, NumberHint);
|
||||
if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b))
|
||||
rval = false;
|
||||
else
|
||||
|
@ -770,7 +770,7 @@
|
|||
}
|
||||
else
|
||||
if (JS2VAL_IS_NUMBER(a)) {
|
||||
b = meta->toPrimitive(b);
|
||||
b = meta->toPrimitive(b, NumberHint);
|
||||
if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b))
|
||||
rval = false;
|
||||
else
|
||||
|
@ -778,7 +778,7 @@
|
|||
}
|
||||
else
|
||||
if (JS2VAL_IS_STRING(a)) {
|
||||
b = meta->toPrimitive(b);
|
||||
b = meta->toPrimitive(b, NumberHint);
|
||||
if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b))
|
||||
rval = false;
|
||||
else
|
||||
|
@ -792,7 +792,7 @@
|
|||
rval = false;
|
||||
else
|
||||
if (JS2VAL_IS_BOOLEAN(b)) {
|
||||
a = meta->toPrimitive(a);
|
||||
a = meta->toPrimitive(a, NumberHint);
|
||||
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
|
||||
rval = false;
|
||||
else
|
||||
|
@ -803,7 +803,7 @@
|
|||
}
|
||||
else
|
||||
if (JS2VAL_IS_NUMBER(b)) {
|
||||
a = meta->toPrimitive(a);
|
||||
a = meta->toPrimitive(a, NumberHint);
|
||||
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
|
||||
rval = false;
|
||||
else
|
||||
|
@ -811,7 +811,7 @@
|
|||
}
|
||||
else
|
||||
if (JS2VAL_IS_STRING(b)) {
|
||||
a = meta->toPrimitive(a);
|
||||
a = meta->toPrimitive(a, NumberHint);
|
||||
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
|
||||
rval = false;
|
||||
else
|
||||
|
|
Загрузка…
Ссылка в новой задаче