1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <qv4runtime_p.h>
41#include <qv4propertykey_p.h>
42#include <qv4string_p.h>
43#include <qv4symbol_p.h>
44#include <qv4object_p.h>
45#include <qv4objectproto_p.h>
46#include <private/qv4mm_p.h>
47
48#include <wtf/MathExtras.h>
49
50using namespace QV4;
51
52int Value::toUInt16() const
53{
54 if (integerCompatible())
55 return (ushort)(uint)integerValue();
56
57 double number = toNumber();
58
59 double D16 = 65536.0;
60 if ((number >= 0 && number < D16))
61 return static_cast<ushort>(number);
62
63 if (!std::isfinite(x: number))
64 return +0;
65
66 double d = ::floor(x: ::fabs(x: number));
67 if (std::signbit(x: number))
68 d = -d;
69
70 number = ::fmod(x: d , y: D16);
71
72 if (number < 0)
73 number += D16;
74
75 return (unsigned short)number;
76}
77
78bool Value::toBooleanImpl(Value val)
79{
80 if (val.isManagedOrUndefined()) {
81 Heap::Base *b = val.m();
82 if (!b)
83 return false;
84 if (b->internalClass->vtable->isString)
85 return static_cast<Heap::String *>(b)->length() > 0;
86 return true;
87 }
88
89 // double
90 double d = val.doubleValue();
91 return d && !std::isnan(x: d);
92}
93
94double Value::toNumberImpl(Value val)
95{
96 switch (val.type()) {
97 case QV4::Value::Undefined_Type:
98 return std::numeric_limits<double>::quiet_NaN();
99 case QV4::Value::Managed_Type:
100 if (String *s = val.stringValue())
101 return RuntimeHelpers::stringToNumber(s: s->toQString());
102 if (val.isSymbol()) {
103 Managed &m = static_cast<Managed &>(val);
104 m.engine()->throwTypeError();
105 return 0;
106 }
107 {
108 Q_ASSERT(val.isObject());
109 Scope scope(val.objectValue()->engine());
110 ScopedValue protectThis(scope, val);
111 ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value: val, typeHint: NUMBER_HINT));
112 if (scope.engine->hasException)
113 return 0;
114 return prim->toNumber();
115 }
116 case QV4::Value::Null_Type:
117 case QV4::Value::Boolean_Type:
118 case QV4::Value::Integer_Type:
119 return val.int_32();
120 default: // double
121 Q_UNREACHABLE();
122 }
123}
124
125QString Value::toQStringNoThrow() const
126{
127 switch (type()) {
128 case Value::Empty_Type:
129 Q_ASSERT(!"empty Value encountered");
130 Q_UNREACHABLE();
131 case Value::Undefined_Type:
132 return QStringLiteral("undefined");
133 case Value::Null_Type:
134 return QStringLiteral("null");
135 case Value::Boolean_Type:
136 if (booleanValue())
137 return QStringLiteral("true");
138 else
139 return QStringLiteral("false");
140 case Value::Managed_Type:
141 if (String *s = stringValue())
142 return s->toQString();
143 if (Symbol *s = symbolValue())
144 return s->descriptiveString();
145 {
146 Q_ASSERT(isObject());
147 Scope scope(objectValue()->engine());
148 ScopedValue ex(scope);
149 bool caughtException = false;
150 ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value: *this, typeHint: STRING_HINT));
151 if (scope.hasException()) {
152 ex = scope.engine->catchException();
153 caughtException = true;
154 } else if (prim->isPrimitive()) {
155 return prim->toQStringNoThrow();
156 }
157 // Can't nest try/catch due to CXX ABI limitations for foreign exception nesting.
158 if (caughtException) {
159 ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value: ex, typeHint: STRING_HINT));
160 if (scope.hasException()) {
161 ex = scope.engine->catchException();
162 } else if (prim->isPrimitive()) {
163 return prim->toQStringNoThrow();
164 }
165 }
166 return QString();
167 }
168 case Value::Integer_Type: {
169 QString str;
170 RuntimeHelpers::numberToString(result: &str, num: (double)int_32(), radix: 10);
171 return str;
172 }
173 default: { // double
174 QString str;
175 RuntimeHelpers::numberToString(result: &str, num: doubleValue(), radix: 10);
176 return str;
177 }
178 } // switch
179}
180
181QString Value::toQString() const
182{
183 switch (type()) {
184 case Value::Empty_Type:
185 Q_ASSERT(!"empty Value encountered");
186 Q_UNREACHABLE();
187 case Value::Undefined_Type:
188 return QStringLiteral("undefined");
189 case Value::Null_Type:
190 return QStringLiteral("null");
191 case Value::Boolean_Type:
192 if (booleanValue())
193 return QStringLiteral("true");
194 else
195 return QStringLiteral("false");
196 case Value::Managed_Type:
197 if (String *s = stringValue()) {
198 return s->toQString();
199 } else if (isSymbol()) {
200 static_cast<const Managed *>(this)->engine()->throwTypeError();
201 return QString();
202 } else {
203 Q_ASSERT(isObject());
204 Scope scope(objectValue()->engine());
205 ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value: *this, typeHint: STRING_HINT));
206 return prim->toQString();
207 }
208 case Value::Integer_Type: {
209 QString str;
210 RuntimeHelpers::numberToString(result: &str, num: (double)int_32(), radix: 10);
211 return str;
212 }
213 default: { // double
214 QString str;
215 RuntimeHelpers::numberToString(result: &str, num: doubleValue(), radix: 10);
216 return str;
217 }
218 } // switch
219}
220
221QV4::PropertyKey Value::toPropertyKey(ExecutionEngine *e) const
222{
223 if (isInteger() && int_32() >= 0)
224 return PropertyKey::fromArrayIndex(idx: static_cast<uint>(int_32()));
225 if (isStringOrSymbol()) {
226 Scope scope(e);
227 ScopedStringOrSymbol s(scope, this);
228 return s->toPropertyKey();
229 }
230 Scope scope(e);
231 ScopedValue v(scope, RuntimeHelpers::toPrimitive(value: *this, typeHint: STRING_HINT));
232 if (!v->isStringOrSymbol())
233 v = v->toString(e);
234 if (e->hasException)
235 return PropertyKey::invalid();
236 ScopedStringOrSymbol s(scope, v);
237 return s->toPropertyKey();
238}
239
240bool Value::sameValue(Value other) const {
241 if (_val == other._val)
242 return true;
243 String *s = stringValue();
244 String *os = other.stringValue();
245 if (s && os)
246 return s->isEqualTo(other: os);
247 if (isInteger() && other.isDouble())
248 return int_32() ? (double(int_32()) == other.doubleValue())
249 : (other.doubleValue() == 0 && !std::signbit(x: other.doubleValue()));
250 if (isDouble() && other.isInteger())
251 return other.int_32() ? (doubleValue() == double(other.int_32()))
252 : (doubleValue() == 0 && !std::signbit(x: doubleValue()));
253 if (isManaged())
254 return other.isManaged() && cast<Managed>()->isEqualTo(other: other.cast<Managed>());
255 return false;
256}
257
258bool Value::sameValueZero(Value other) const {
259 if (_val == other._val)
260 return true;
261 String *s = stringValue();
262 String *os = other.stringValue();
263 if (s && os)
264 return s->isEqualTo(other: os);
265 if (isInteger() && other.isDouble())
266 return double(int_32()) == other.doubleValue();
267 if (isDouble() && other.isInteger())
268 return other.int_32() == doubleValue();
269 if (isDouble() && other.isDouble()) {
270 if (doubleValue() == 0 && other.doubleValue() == 0) {
271 return true;
272 }
273 }
274 if (isManaged())
275 return other.isManaged() && cast<Managed>()->isEqualTo(other: other.cast<Managed>());
276 return false;
277}
278
279Heap::String *Value::toString(ExecutionEngine *e, Value val)
280{
281 return RuntimeHelpers::convertToString(engine: e, value: val);
282}
283
284Heap::Object *Value::toObject(ExecutionEngine *e, Value val)
285{
286 return RuntimeHelpers::convertToObject(engine: e, value: val);
287}
288
289uint Value::asArrayLength(bool *ok) const
290{
291 *ok = true;
292 if (isInteger()) {
293 if (int_32() >= 0) {
294 return (uint)int_32();
295 } else {
296 *ok = false;
297 return UINT_MAX;
298 }
299 }
300 if (isNumber()) {
301 double d = doubleValue();
302 uint idx = (uint)d;
303 if (idx != d) {
304 *ok = false;
305 return UINT_MAX;
306 }
307 return idx;
308 }
309 if (String *s = stringValue())
310 return s->toUInt(ok);
311
312 uint idx = toUInt32();
313 double d = toNumber();
314 if (d != idx) {
315 *ok = false;
316 return UINT_MAX;
317 }
318 return idx;
319}
320

source code of qtdeclarative/src/qml/jsruntime/qv4value.cpp