diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-12-11 13:35:53 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-12-18 17:26:51 +0100 |
commit | 6f181768a3147bbfa9a33cf2c05453365693f5b9 (patch) | |
tree | 3ff80238b5784032c86cfc1a70088e17b62a7127 /src/qml/jsruntime/qv4value.cpp | |
parent | d5ac54da624dbaebc865c8243a5e1c33d5e1c7ba (diff) |
Add a QJSManagedValue
A QJSManagedValue is a view on a QJSValue which always knows the engine
the value belongs to. This allows us to implement the JavaScript
semantics of the various QJSValue methods in a much more rigorous way.
[ChangeLog][QtQml] The new QJSManagedValue should be used instead of
QJSValue for manipulating properties and prototypes of JavaScript
values, as well as for calling JavaScript functions.
Change-Id: I9d445ffcf68dfa72dba9bae0818e83c80665ad66
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4value.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4value.cpp | 147 |
1 files changed, 86 insertions, 61 deletions
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 3449603a8a..6913a49f9c 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -122,100 +122,125 @@ double Value::toNumberImpl(Value val) } } -QString Value::toQStringNoThrow() const +static QString primitiveToQString(const Value *value) { - switch (type()) { + switch (value->type()) { case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); Q_UNREACHABLE(); + return QString(); case Value::Undefined_Type: return QStringLiteral("undefined"); case Value::Null_Type: return QStringLiteral("null"); case Value::Boolean_Type: - if (booleanValue()) + if (value->booleanValue()) return QStringLiteral("true"); else return QStringLiteral("false"); case Value::Managed_Type: + Q_UNREACHABLE(); + return QString(); + case Value::Integer_Type: { + QString str; + RuntimeHelpers::numberToString(&str, (double)value->int_32(), 10); + return str; + } + case Value::Double_Type: { + QString str; + RuntimeHelpers::numberToString(&str, value->doubleValue(), 10); + return str; + } + } // switch + + Q_UNREACHABLE(); + return QString(); +} + + +QString Value::toQStringNoThrow() const +{ + if (isManaged()) { if (String *s = stringValue()) return s->toQString(); if (Symbol *s = symbolValue()) return s->descriptiveString(); - { - Q_ASSERT(isObject()); - Scope scope(objectValue()->engine()); - ScopedValue ex(scope); - bool caughtException = false; - ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT)); + + Q_ASSERT(isObject()); + Scope scope(objectValue()->engine()); + ScopedValue ex(scope); + bool caughtException = false; + ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT)); + if (scope.hasException()) { + ex = scope.engine->catchException(); + caughtException = true; + } else if (prim->isPrimitive()) { + return prim->toQStringNoThrow(); + } + + // Can't nest try/catch due to CXX ABI limitations for foreign exception nesting. + if (caughtException) { + ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ex, STRING_HINT)); if (scope.hasException()) { ex = scope.engine->catchException(); - caughtException = true; } else if (prim->isPrimitive()) { - return prim->toQStringNoThrow(); - } - // Can't nest try/catch due to CXX ABI limitations for foreign exception nesting. - if (caughtException) { - ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ex, STRING_HINT)); - if (scope.hasException()) { - ex = scope.engine->catchException(); - } else if (prim->isPrimitive()) { - return prim->toQStringNoThrow(); - } + return prim->toQStringNoThrow(); } - return QString(); } - case Value::Integer_Type: { - QString str; - RuntimeHelpers::numberToString(&str, (double)int_32(), 10); - return str; - } - default: { // double - QString str; - RuntimeHelpers::numberToString(&str, doubleValue(), 10); - return str; + + return QString(); } - } // switch + + return primitiveToQString(this); } QString Value::toQString() const { - switch (type()) { - case Value::Empty_Type: - Q_ASSERT(!"empty Value encountered"); - Q_UNREACHABLE(); - case Value::Undefined_Type: - return QStringLiteral("undefined"); - case Value::Null_Type: - return QStringLiteral("null"); - case Value::Boolean_Type: - if (booleanValue()) - return QStringLiteral("true"); - else - return QStringLiteral("false"); - case Value::Managed_Type: - if (String *s = stringValue()) { + if (isManaged()) { + if (String *s = stringValue()) return s->toQString(); - } else if (isSymbol()) { + + if (isSymbol()) { static_cast<const Managed *>(this)->engine()->throwTypeError(); return QString(); - } else { - Q_ASSERT(isObject()); - Scope scope(objectValue()->engine()); - ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT)); - return prim->toQString(); } - case Value::Integer_Type: { - QString str; - RuntimeHelpers::numberToString(&str, (double)int_32(), 10); - return str; + + Q_ASSERT(isObject()); + Scope scope(objectValue()->engine()); + ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT)); + return prim->toQString(); } - default: { // double - QString str; - RuntimeHelpers::numberToString(&str, doubleValue(), 10); - return str; + + return primitiveToQString(this); +} + +QString Value::toQString(bool *ok) const +{ + if (isManaged()) { + if (String *s = stringValue()) { + *ok = true; + return s->toQString(); + } + + if (isSymbol()) { + static_cast<const Managed *>(this)->engine()->throwTypeError(); + *ok = false; + return QString(); + } + + Q_ASSERT(isObject()); + Scope scope(objectValue()->engine()); + ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT)); + + if (scope.hasException()) { + *ok = false; + return QString(); + } + + return prim->toQString(ok); } - } // switch + + return primitiveToQString(this); } QV4::PropertyKey Value::toPropertyKey(ExecutionEngine *e) const |