diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-05-27 22:58:32 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-05-28 10:40:08 +0000 |
commit | 3ccd529e350fdf20ad3fb7b296220d63f8bcc747 (patch) | |
tree | c755f0c029543fbf2afd510156e1d51c28a8b28b /src/qml | |
parent | 23aa9d58d006dd50adb3f582df9b7dab4f64be0b (diff) |
Implement toPrimitive() the way the ES7 spec wants it
Add Dat.prototype[Symbol.toPrimitive] and make use of those
methods in the toPrimitive implementation.
Change-Id: I82a9a94dcae6822100de364373b3f4de1e3d749b
Reviewed-by: Robin Burchell <robin.burchell@crimson.no>
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/jsruntime/qv4dateobject.cpp | 18 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4dateobject_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 49 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 10 |
7 files changed, 68 insertions, 14 deletions
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index e9a2056a61..092c36e52a 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -44,6 +44,7 @@ #include "qv4runtime_p.h" #include "qv4string_p.h" #include "qv4jscall_p.h" +#include "qv4symbol_p.h" #include <QtCore/QDebug> #include <QtCore/QDateTime> @@ -859,6 +860,7 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("toISOString"), method_toISOString, 0); defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1); + defineDefaultProperty(engine->symbol_toPrimitive(), method_symbolToPrimitive, 1, Attr_ReadOnly_ButConfigurable); } double DatePrototype::getThisDate(ExecutionEngine *v4, const Value *thisObject) @@ -1515,6 +1517,22 @@ ReturnedValue DatePrototype::method_toJSON(const FunctionObject *b, const Value return toIso->call(O, nullptr, 0); } +ReturnedValue DatePrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) +{ + ExecutionEngine *e = f->engine(); + if (!thisObject->isObject() || !argc || !argv->isString()) + return e->throwTypeError(); + + String *hint = argv->stringValue(); + Identifier id = hint->identifier(); + if (id == e->id_default()->identifier()) + hint = e->id_string(); + else if (id != e->id_string()->identifier() && id != e->id_number()->identifier()) + return e->throwTypeError(); + + return RuntimeHelpers::ordinaryToPrimitive(e, static_cast<const Object *>(thisObject), hint); +} + void DatePrototype::timezoneUpdated(ExecutionEngine *e) { e->localTZA = getLocalTZA(); diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index 1ee514f599..0a5a3954d1 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -169,6 +169,7 @@ struct DatePrototype: Object static ReturnedValue method_toUTCString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_toISOString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_toJSON(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *, int); static void timezoneUpdated(ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index fbe9db7075..87132f64bb 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -240,6 +240,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) jsStrings[String_boolean] = newIdentifier(QStringLiteral("boolean")); jsStrings[String_number] = newIdentifier(QStringLiteral("number")); jsStrings[String_string] = newIdentifier(QStringLiteral("string")); + jsStrings[String_default] = newIdentifier(QStringLiteral("default")); jsStrings[String_symbol] = newIdentifier(QStringLiteral("symbol")); jsStrings[String_object] = newIdentifier(QStringLiteral("object")); jsStrings[String_function] = newIdentifier(QStringLiteral("function")); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 9206fdc0bb..155383c55d 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -304,6 +304,7 @@ public: String_boolean, String_number, String_string, + String_default, String_symbol, String_object, String_function, @@ -365,6 +366,7 @@ public: String *id_boolean() const { return reinterpret_cast<String *>(jsStrings + String_boolean); } String *id_number() const { return reinterpret_cast<String *>(jsStrings + String_number); } String *id_string() const { return reinterpret_cast<String *>(jsStrings + String_string); } + String *id_default() const { return reinterpret_cast<String *>(jsStrings + String_default); } String *id_symbol() const { return reinterpret_cast<String *>(jsStrings + String_symbol); } String *id_object() const { return reinterpret_cast<String *>(jsStrings + String_object); } String *id_function() const { return reinterpret_cast<String *>(jsStrings + String_function); } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 6eff9c50db..3cc1943427 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -420,27 +420,59 @@ Heap::String *RuntimeHelpers::stringFromNumber(ExecutionEngine *engine, double n ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeHint) { - if (typeHint == PREFERREDTYPE_HINT) { - if (object->as<DateObject>()) - typeHint = STRING_HINT; - else - typeHint = NUMBER_HINT; + ExecutionEngine *engine = object->internalClass()->engine; + if (engine->hasException) + return Encode::undefined(); + + String *hint; + switch (typeHint) { + case STRING_HINT: + hint = engine->id_string(); + break; + case NUMBER_HINT: + hint = engine->id_number(); + break; + default: + hint = engine->id_default(); + break; } - ExecutionEngine *engine = object->internalClass()->engine; + Scope scope(engine); + ScopedFunctionObject toPrimitive(scope, object->get(engine->symbol_toPrimitive())); if (engine->hasException) return Encode::undefined(); + if (toPrimitive) { + ScopedValue result(scope, toPrimitive->call(object, hint, 1)); + if (engine->hasException) + return Encode::undefined(); + if (!result->isPrimitive()) + return engine->throwTypeError(); + return result->asReturnedValue(); + } + + if (hint == engine->id_default()) + hint = engine->id_number(); + return ordinaryToPrimitive(engine, object, hint); +} + + +ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const Object *object, String *typeHint) +{ + Q_ASSERT(!engine->hasException); String *meth1 = engine->id_toString(); String *meth2 = engine->id_valueOf(); - if (typeHint == NUMBER_HINT) + if (typeHint->identifier() == engine->id_number()->identifier()) { qSwap(meth1, meth2); + } else { + Q_ASSERT(typeHint->identifier() == engine->id_string()->identifier()); + } Scope scope(engine); ScopedValue result(scope); - ScopedValue conv(scope, object->get(meth1)); + ScopedValue conv(scope, object->get(meth1)); if (FunctionObject *o = conv->as<FunctionObject>()) { result = o->call(object, nullptr, 0); if (result->isPrimitive()) @@ -461,7 +493,6 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH } - Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Value &value) { Q_ASSERT(!value.isObject()); diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 3a26c23990..72af90d1dc 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -100,6 +100,7 @@ enum TypeHint { struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { static ReturnedValue objectDefaultValue(const Object *object, int typeHint); static ReturnedValue toPrimitive(const Value &value, TypeHint typeHint); + static ReturnedValue ordinaryToPrimitive(ExecutionEngine *engine, const Object *object, String *typeHint); static double stringToNumber(const QString &s); static Heap::String *stringFromNumber(ExecutionEngine *engine, double number); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index d89d314942..bf07faca2a 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -398,13 +398,13 @@ static bool compareEqual(QV4::Value lhs, QV4::Value rhs) Heap::Base *r = rhs.m(); Q_ASSERT(l); Q_ASSERT(r); - if (l->internalClass->vtable->isString == r->internalClass->vtable->isString) + if (l->internalClass->vtable->isStringOrSymbol == r->internalClass->vtable->isStringOrSymbol) return static_cast<QV4::Managed &>(lhs).isEqualTo(&static_cast<QV4::Managed &>(rhs)); - if (l->internalClass->vtable->isString) { + if (l->internalClass->vtable->isStringOrSymbol) { rhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(rhs), PREFERREDTYPE_HINT)); break; } else { - Q_ASSERT(r->internalClass->vtable->isString); + Q_ASSERT(r->internalClass->vtable->isStringOrSymbol); lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT)); break; } @@ -419,8 +419,8 @@ static bool compareEqual(QV4::Value lhs, QV4::Value rhs) rhs = Primitive::fromDouble(rhs.int_32()); // fall through default: // double - if (lhs.m()->internalClass->vtable->isString) - return RuntimeHelpers::toNumber(lhs) == rhs.doubleValue(); + if (lhs.m()->internalClass->vtable->isStringOrSymbol) + return lhs.m()->internalClass->vtable->isString ? (RuntimeHelpers::toNumber(lhs) == rhs.doubleValue()) : false; else lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT)); } |