ECMA3 semantics for toPrimitive.

This commit is contained in:
rogerl%netscape.com 2003-01-13 18:47:54 +00:00
Родитель b2486b2092
Коммит 736c95e712
6 изменённых файлов: 89 добавлений и 48 удалений

Просмотреть файл

@ -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