1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** This file is part of the QtScript module of the Qt Toolkit.
|
---|
7 | **
|
---|
8 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
9 | ** Commercial Usage
|
---|
10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
11 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
12 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
13 | ** a written agreement between you and Nokia.
|
---|
14 | **
|
---|
15 | ** GNU Lesser General Public License Usage
|
---|
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
17 | ** General Public License version 2.1 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
19 | ** packaging of this file. Please review the following information to
|
---|
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
22 | **
|
---|
23 | ** In addition, as a special exception, Nokia gives you certain
|
---|
24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
---|
25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
---|
26 | ** package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you are unsure which license is appropriate for your use, please
|
---|
37 | ** contact the sales department at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "qscriptecmaarray_p.h"
|
---|
43 |
|
---|
44 | #ifndef QT_NO_SCRIPT
|
---|
45 |
|
---|
46 | #include "qscriptengine_p.h"
|
---|
47 | #include "qscriptvalueimpl_p.h"
|
---|
48 | #include "qscriptcontext_p.h"
|
---|
49 | #include "qscriptmember_p.h"
|
---|
50 | #include "qscriptobject_p.h"
|
---|
51 | #include "qscriptclassdata_p.h"
|
---|
52 |
|
---|
53 | #include <QtCore/QtDebug>
|
---|
54 |
|
---|
55 | QT_BEGIN_NAMESPACE
|
---|
56 |
|
---|
57 | namespace QScript { namespace Ecma {
|
---|
58 |
|
---|
59 | class ArrayClassData: public QScriptClassData
|
---|
60 | {
|
---|
61 | QScriptClassInfo *m_classInfo;
|
---|
62 |
|
---|
63 | public:
|
---|
64 | ArrayClassData(QScriptClassInfo *classInfo);
|
---|
65 | virtual ~ArrayClassData();
|
---|
66 |
|
---|
67 | inline QScriptClassInfo *classInfo() const
|
---|
68 | { return m_classInfo; }
|
---|
69 |
|
---|
70 | virtual void mark(const QScriptValueImpl &object, int generation);
|
---|
71 | virtual bool resolve(const QScriptValueImpl &object,
|
---|
72 | QScriptNameIdImpl *nameId,
|
---|
73 | QScript::Member *member,
|
---|
74 | QScriptValueImpl *base,
|
---|
75 | QScript::AccessMode mode);
|
---|
76 | virtual bool get(const QScriptValueImpl &obj, const Member &m,
|
---|
77 | QScriptValueImpl *out_value);
|
---|
78 | virtual bool put(QScriptValueImpl *object, const Member &member,
|
---|
79 | const QScriptValueImpl &value);
|
---|
80 | virtual bool removeMember(const QScriptValueImpl &object,
|
---|
81 | const QScript::Member &member);
|
---|
82 | virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object);
|
---|
83 | };
|
---|
84 |
|
---|
85 | class ArrayClassDataIterator: public QScriptClassDataIterator
|
---|
86 | {
|
---|
87 | public:
|
---|
88 | ArrayClassDataIterator(Array::Instance *instance);
|
---|
89 | virtual ~ArrayClassDataIterator();
|
---|
90 |
|
---|
91 | virtual bool hasNext() const;
|
---|
92 | virtual void next(QScript::Member *member);
|
---|
93 |
|
---|
94 | virtual bool hasPrevious() const;
|
---|
95 | virtual void previous(QScript::Member *member);
|
---|
96 |
|
---|
97 | virtual void toFront();
|
---|
98 | virtual void toBack();
|
---|
99 |
|
---|
100 | private:
|
---|
101 | Array::Instance *m_instance;
|
---|
102 | QList<uint> m_keys;
|
---|
103 | quint32 m_pos;
|
---|
104 | };
|
---|
105 |
|
---|
106 | ArrayClassData::ArrayClassData(QScriptClassInfo *classInfo):
|
---|
107 | m_classInfo(classInfo)
|
---|
108 | {
|
---|
109 | }
|
---|
110 |
|
---|
111 | ArrayClassData::~ArrayClassData()
|
---|
112 | {
|
---|
113 | }
|
---|
114 |
|
---|
115 | void ArrayClassData::mark(const QScriptValueImpl &object, int generation)
|
---|
116 | {
|
---|
117 | Array::Instance *instance = Array::Instance::get(object, classInfo());
|
---|
118 | if (! instance)
|
---|
119 | return;
|
---|
120 |
|
---|
121 | instance->value.mark(generation);
|
---|
122 | }
|
---|
123 |
|
---|
124 | bool ArrayClassData::resolve(const QScriptValueImpl &object,
|
---|
125 | QScriptNameIdImpl *nameId,
|
---|
126 | QScript::Member *member,
|
---|
127 | QScriptValueImpl *base,
|
---|
128 | QScript::AccessMode access)
|
---|
129 | {
|
---|
130 | QScriptEnginePrivate *eng_p = object.engine();
|
---|
131 |
|
---|
132 | Array::Instance *instance = Array::Instance::get(object, classInfo());
|
---|
133 | if (!instance)
|
---|
134 | return false;
|
---|
135 |
|
---|
136 | if (nameId == eng_p->idTable()->id_length) {
|
---|
137 | member->native(nameId, /*id=*/ 0,
|
---|
138 | QScriptValue::Undeletable
|
---|
139 | | QScriptValue::SkipInEnumeration);
|
---|
140 | *base = object;
|
---|
141 | return true;
|
---|
142 | }
|
---|
143 |
|
---|
144 | QString propertyName = eng_p->toString(nameId);
|
---|
145 | bool isNumber;
|
---|
146 | quint32 pos = propertyName.toUInt(&isNumber);
|
---|
147 |
|
---|
148 | if (!isNumber || (pos == 0xFFFFFFFF)
|
---|
149 | || (QScriptValueImpl(pos).toString() != propertyName)) { // ### improve me
|
---|
150 | return false;
|
---|
151 | }
|
---|
152 |
|
---|
153 | if ((access == QScript::Read) && ((pos >= instance->value.count()) || !instance->value.at(pos).isValid()))
|
---|
154 | return false;
|
---|
155 |
|
---|
156 | member->native(0, pos, /*flags=*/0);
|
---|
157 | *base = object;
|
---|
158 | return true;
|
---|
159 | }
|
---|
160 |
|
---|
161 | bool ArrayClassData::get(const QScriptValueImpl &object,
|
---|
162 | const QScript::Member &member,
|
---|
163 | QScriptValueImpl *result)
|
---|
164 | {
|
---|
165 | Q_ASSERT(member.isValid());
|
---|
166 |
|
---|
167 | if (! member.isNativeProperty())
|
---|
168 | return false;
|
---|
169 |
|
---|
170 | QScriptEnginePrivate *eng = object.engine();
|
---|
171 |
|
---|
172 | Array::Instance *instance = Array::Instance::get(object, classInfo());
|
---|
173 | if (! instance)
|
---|
174 | return false;
|
---|
175 |
|
---|
176 | if (member.nameId() == eng->idTable()->id_length)
|
---|
177 | *result = QScriptValueImpl(instance->value.count());
|
---|
178 |
|
---|
179 | else {
|
---|
180 | quint32 pos = quint32 (member.id());
|
---|
181 |
|
---|
182 | if (pos < instance->value.count())
|
---|
183 | *result = instance->value.at(pos);
|
---|
184 | else
|
---|
185 | *result = eng->undefinedValue();
|
---|
186 | }
|
---|
187 |
|
---|
188 | return true;
|
---|
189 | }
|
---|
190 |
|
---|
191 | bool ArrayClassData::put(QScriptValueImpl *object,
|
---|
192 | const QScript::Member &member,
|
---|
193 | const QScriptValueImpl &value)
|
---|
194 | {
|
---|
195 | Q_ASSERT(object != 0);
|
---|
196 | Q_ASSERT(member.isValid());
|
---|
197 |
|
---|
198 | if (! member.isNativeProperty())
|
---|
199 | return false;
|
---|
200 |
|
---|
201 | Array::Instance *instance = Array::Instance::get(*object, classInfo());
|
---|
202 | if (! instance)
|
---|
203 | return false;
|
---|
204 |
|
---|
205 | QScriptEnginePrivate *eng_p = object->engine();
|
---|
206 |
|
---|
207 | if (member.nameId() == eng_p->idTable()->id_length) {
|
---|
208 | qsreal length = value.toNumber();
|
---|
209 | quint32 len = eng_p->toUint32(length);
|
---|
210 | instance->value.resize(len);
|
---|
211 | }
|
---|
212 |
|
---|
213 | else if (member.nameId() == 0) {
|
---|
214 | quint32 pos = quint32 (member.id());
|
---|
215 | instance->value.assign(pos, value);
|
---|
216 | }
|
---|
217 |
|
---|
218 | return true;
|
---|
219 | }
|
---|
220 |
|
---|
221 | bool ArrayClassData::removeMember(const QScriptValueImpl &object,
|
---|
222 | const QScript::Member &member)
|
---|
223 | {
|
---|
224 | if (!member.isNativeProperty() || !member.isDeletable() || (member.nameId() != 0))
|
---|
225 | return false;
|
---|
226 |
|
---|
227 | Array::Instance *instance = Array::Instance::get(object, classInfo());
|
---|
228 | if (! instance)
|
---|
229 | return false;
|
---|
230 |
|
---|
231 | quint32 pos = quint32 (member.id());
|
---|
232 | if (instance->value.at(pos).isValid())
|
---|
233 | instance->value.assign(pos, QScriptValueImpl());
|
---|
234 | return true;
|
---|
235 | }
|
---|
236 |
|
---|
237 | QScriptClassDataIterator *ArrayClassData::newIterator(const QScriptValueImpl &object)
|
---|
238 | {
|
---|
239 | Array::Instance *instance = Array::Instance::get(object, classInfo());
|
---|
240 | return new ArrayClassDataIterator(instance);
|
---|
241 | }
|
---|
242 |
|
---|
243 | ArrayClassDataIterator::ArrayClassDataIterator(Array::Instance *instance)
|
---|
244 | {
|
---|
245 | m_instance = instance;
|
---|
246 | toFront();
|
---|
247 | }
|
---|
248 |
|
---|
249 | ArrayClassDataIterator::~ArrayClassDataIterator()
|
---|
250 | {
|
---|
251 | }
|
---|
252 |
|
---|
253 | bool ArrayClassDataIterator::hasNext() const
|
---|
254 | {
|
---|
255 | quint32 limit = m_keys.isEmpty() ? m_instance->value.size() : quint32(m_keys.size());
|
---|
256 | for (quint32 i = m_pos; i < limit; ++i) {
|
---|
257 | quint32 realI = m_keys.isEmpty() ? i : m_keys.at(i);
|
---|
258 | if (m_instance->value.at(realI).isValid())
|
---|
259 | return true;
|
---|
260 | }
|
---|
261 | return false;
|
---|
262 | }
|
---|
263 |
|
---|
264 | void ArrayClassDataIterator::next(QScript::Member *member)
|
---|
265 | {
|
---|
266 | quint32 limit = m_keys.isEmpty() ? m_instance->value.size() : quint32(m_keys.size());
|
---|
267 | for (quint32 i = m_pos; i < limit; ++i) {
|
---|
268 | quint32 realI = m_keys.isEmpty() ? i : m_keys.at(i);
|
---|
269 | if (m_instance->value.at(realI).isValid()) {
|
---|
270 | member->native(/*nameId=*/0, realI, /*flags=*/0);
|
---|
271 | m_pos = i + 1;
|
---|
272 | return;
|
---|
273 | }
|
---|
274 | }
|
---|
275 | member->invalidate();
|
---|
276 | }
|
---|
277 |
|
---|
278 | bool ArrayClassDataIterator::hasPrevious() const
|
---|
279 | {
|
---|
280 | for (quint32 i = m_pos - 1; i != 0xFFFFFFFF; --i) {
|
---|
281 | quint32 realI = m_keys.isEmpty() ? i : m_keys.at(i);
|
---|
282 | if (m_instance->value.at(realI).isValid())
|
---|
283 | return true;
|
---|
284 | }
|
---|
285 | return false;
|
---|
286 | }
|
---|
287 |
|
---|
288 | void ArrayClassDataIterator::previous(QScript::Member *member)
|
---|
289 | {
|
---|
290 | for (quint32 i = m_pos - 1; i != 0xFFFFFFFF; --i) {
|
---|
291 | quint32 realI = m_keys.isEmpty() ? i : m_keys.at(i);
|
---|
292 | if (m_instance->value.at(realI).isValid()) {
|
---|
293 | member->native(/*nameId=*/ 0, realI, /*flags=*/0);
|
---|
294 | m_pos = i;
|
---|
295 | return;
|
---|
296 | }
|
---|
297 | }
|
---|
298 | member->invalidate();
|
---|
299 | }
|
---|
300 |
|
---|
301 | void ArrayClassDataIterator::toFront()
|
---|
302 | {
|
---|
303 | m_keys = m_instance->value.keys();
|
---|
304 | m_pos = 0;
|
---|
305 | }
|
---|
306 |
|
---|
307 | void ArrayClassDataIterator::toBack()
|
---|
308 | {
|
---|
309 | m_keys = m_instance->value.keys();
|
---|
310 | m_pos = m_keys.isEmpty() ? m_instance->value.count() : m_keys.size();
|
---|
311 | }
|
---|
312 |
|
---|
313 |
|
---|
314 |
|
---|
315 | Array::Array(QScriptEnginePrivate *eng):
|
---|
316 | Core(eng, QLatin1String("Array"), QScriptClassInfo::ArrayType)
|
---|
317 | {
|
---|
318 | classInfo()->setData(new ArrayClassData(classInfo()));
|
---|
319 |
|
---|
320 | newArray(&publicPrototype, QScript::Array(eng));
|
---|
321 |
|
---|
322 | eng->newConstructor(&ctor, this, publicPrototype);
|
---|
323 |
|
---|
324 | addPrototypeFunction(QLatin1String("toString"), method_toString, 0);
|
---|
325 | addPrototypeFunction(QLatin1String("toLocaleString"), method_toLocaleString, 0);
|
---|
326 | addPrototypeFunction(QLatin1String("concat"), method_concat, 1);
|
---|
327 | addPrototypeFunction(QLatin1String("join"), method_join, 1);
|
---|
328 | addPrototypeFunction(QLatin1String("pop"), method_pop, 0);
|
---|
329 | addPrototypeFunction(QLatin1String("push"), method_push, 1);
|
---|
330 | addPrototypeFunction(QLatin1String("reverse"), method_reverse, 0);
|
---|
331 | addPrototypeFunction(QLatin1String("shift"), method_shift, 0);
|
---|
332 | addPrototypeFunction(QLatin1String("slice"), method_slice, 2);
|
---|
333 | addPrototypeFunction(QLatin1String("sort"), method_sort, 1);
|
---|
334 | addPrototypeFunction(QLatin1String("splice"), method_splice, 2);
|
---|
335 | addPrototypeFunction(QLatin1String("unshift"), method_unshift, 1);
|
---|
336 | }
|
---|
337 |
|
---|
338 | Array::~Array()
|
---|
339 | {
|
---|
340 | }
|
---|
341 |
|
---|
342 | void Array::execute(QScriptContextPrivate *context)
|
---|
343 | {
|
---|
344 | #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
|
---|
345 | engine()->notifyFunctionEntry(context);
|
---|
346 | #endif
|
---|
347 | QScript::Array value(engine());
|
---|
348 |
|
---|
349 | if (context->argumentCount() == 1 && context->argument(0).isNumber()) {
|
---|
350 | qsreal size = context->argument(0).toNumber();
|
---|
351 | quint32 isize = QScriptEnginePrivate::toUint32(size);
|
---|
352 |
|
---|
353 | if (size != qsreal(isize)) {
|
---|
354 | context->throwError(QScriptContext::RangeError, QLatin1String("invalid array length"));
|
---|
355 | return;
|
---|
356 | }
|
---|
357 |
|
---|
358 | value.resize(isize);
|
---|
359 | } else {
|
---|
360 | for (int i = 0; i < context->argumentCount(); ++i) {
|
---|
361 | value.assign(i, context->argument(i));
|
---|
362 | }
|
---|
363 | }
|
---|
364 |
|
---|
365 | if (context->isCalledAsConstructor()) {
|
---|
366 | QScriptValueImpl &object = context->m_thisObject;
|
---|
367 | object.setClassInfo(classInfo());
|
---|
368 | object.setPrototype(publicPrototype);
|
---|
369 | initArray(&object, value);
|
---|
370 | } else {
|
---|
371 | newArray(&context->m_result, value);
|
---|
372 | }
|
---|
373 |
|
---|
374 | #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
|
---|
375 | engine()->notifyFunctionExit(context);
|
---|
376 | #endif
|
---|
377 | }
|
---|
378 |
|
---|
379 | void Array::newArray(QScriptValueImpl *result, const QScript::Array &value)
|
---|
380 | {
|
---|
381 | engine()->newObject(result, publicPrototype, classInfo());
|
---|
382 | initArray(result, value);
|
---|
383 | }
|
---|
384 |
|
---|
385 | void Array::initArray(QScriptValueImpl *result, const QScript::Array &value)
|
---|
386 | {
|
---|
387 | Instance *instance = new Instance(engine());
|
---|
388 | instance->value = value;
|
---|
389 | result->setObjectData(instance);
|
---|
390 | }
|
---|
391 |
|
---|
392 | QScriptValueImpl Array::method_toString(QScriptContextPrivate *context,
|
---|
393 | QScriptEnginePrivate *eng,
|
---|
394 | QScriptClassInfo *classInfo)
|
---|
395 | {
|
---|
396 | return method_join(context, eng, classInfo); // ### fixme
|
---|
397 | }
|
---|
398 |
|
---|
399 | QScriptValueImpl Array::method_toLocaleString(QScriptContextPrivate *context,
|
---|
400 | QScriptEnginePrivate *eng,
|
---|
401 | QScriptClassInfo *classInfo)
|
---|
402 | {
|
---|
403 | return method_toString(context, eng, classInfo);
|
---|
404 | }
|
---|
405 |
|
---|
406 | QScriptValueImpl Array::method_concat(QScriptContextPrivate *context,
|
---|
407 | QScriptEnginePrivate *eng,
|
---|
408 | QScriptClassInfo *classInfo)
|
---|
409 | {
|
---|
410 | QScript::Array result(eng);
|
---|
411 |
|
---|
412 | if (Instance *instance = Instance::get(context->thisObject(), classInfo))
|
---|
413 | result = instance->value;
|
---|
414 |
|
---|
415 | else {
|
---|
416 | QString v = context->thisObject().toString();
|
---|
417 | result.assign(0, QScriptValueImpl(eng, v));
|
---|
418 | }
|
---|
419 |
|
---|
420 | for (int i = 0; i < context->argumentCount(); ++i) {
|
---|
421 | quint32 k = result.size();
|
---|
422 | QScriptValueImpl arg = context->argument(i);
|
---|
423 |
|
---|
424 | if (Instance *elt = Instance::get(arg, classInfo))
|
---|
425 | result.concat(elt->value);
|
---|
426 |
|
---|
427 | else
|
---|
428 | result.assign(k, QScriptValueImpl(eng, arg.toString()));
|
---|
429 | }
|
---|
430 |
|
---|
431 | return eng->newArray(result);
|
---|
432 | }
|
---|
433 |
|
---|
434 | QScriptValueImpl Array::method_join(QScriptContextPrivate *context,
|
---|
435 | QScriptEnginePrivate *eng,
|
---|
436 | QScriptClassInfo *)
|
---|
437 | {
|
---|
438 | QScriptValueImpl arg = context->argument(0);
|
---|
439 |
|
---|
440 | QString r4;
|
---|
441 | if (arg.isUndefined())
|
---|
442 | r4 = QLatin1String(",");
|
---|
443 | else
|
---|
444 | r4 = arg.toString();
|
---|
445 |
|
---|
446 | QScriptValueImpl self = context->thisObject();
|
---|
447 |
|
---|
448 | QScriptNameIdImpl *id_length = eng->idTable()->id_length;
|
---|
449 | QScriptValueImpl length = self.property(id_length);
|
---|
450 | qsreal r1 = length.isValid() ? length.toNumber() : 0;
|
---|
451 | quint32 r2 = QScriptEnginePrivate::toUint32(r1);
|
---|
452 |
|
---|
453 | if (! r2)
|
---|
454 | return QScriptValueImpl(eng, QString());
|
---|
455 |
|
---|
456 | if (eng->visitedArrayElements.contains(self.objectValue())) {
|
---|
457 | // avoid infinite recursion
|
---|
458 | return QScriptValueImpl(eng, QString());
|
---|
459 | }
|
---|
460 | eng->visitedArrayElements.insert(self.objectValue());
|
---|
461 |
|
---|
462 | QString R;
|
---|
463 |
|
---|
464 | QScriptValueImpl r6 = self.property(QLatin1String("0"));
|
---|
465 | if (r6.isValid() && !(r6.isUndefined() || r6.isNull()))
|
---|
466 | R = r6.toString();
|
---|
467 |
|
---|
468 | for (quint32 k = 1; k < r2; ++k) {
|
---|
469 | R += r4;
|
---|
470 |
|
---|
471 | QScriptNameIdImpl *name = eng->nameId(QScriptValueImpl(k).toString());
|
---|
472 | QScriptValueImpl r12 = self.property(name);
|
---|
473 |
|
---|
474 | if (r12.isValid() && ! (r12.isUndefined() || r12.isNull()))
|
---|
475 | R += r12.toString();
|
---|
476 | }
|
---|
477 |
|
---|
478 | eng->visitedArrayElements.remove(self.objectValue());
|
---|
479 | return QScriptValueImpl(eng, R);
|
---|
480 | }
|
---|
481 |
|
---|
482 | QScriptValueImpl Array::method_pop(QScriptContextPrivate *context,
|
---|
483 | QScriptEnginePrivate *eng,
|
---|
484 | QScriptClassInfo *classInfo)
|
---|
485 | {
|
---|
486 | QScriptValueImpl self = context->thisObject();
|
---|
487 | if (Instance *instance = Instance::get(self, classInfo)) {
|
---|
488 | QScriptValueImpl elt = instance->value.pop();
|
---|
489 | if (! elt.isValid())
|
---|
490 | elt = eng->undefinedValue();
|
---|
491 |
|
---|
492 | return elt;
|
---|
493 | }
|
---|
494 |
|
---|
495 | QScriptNameIdImpl *id_length = eng->idTable()->id_length;
|
---|
496 |
|
---|
497 | QScriptValueImpl r1 = self.property(id_length);
|
---|
498 | quint32 r2 = r1.toUInt32();
|
---|
499 | if (! r2) {
|
---|
500 | self.setProperty(id_length, QScriptValueImpl(0));
|
---|
501 | return eng->undefinedValue();
|
---|
502 | }
|
---|
503 | QScriptNameIdImpl *r6 = eng->nameId(QScriptValueImpl(r2 - 1).toString());
|
---|
504 | QScriptValueImpl r7 = self.property(r6);
|
---|
505 | self.deleteProperty(r6);
|
---|
506 | self.setProperty(id_length, QScriptValueImpl(r2 - 1));
|
---|
507 | if (!r7.isValid())
|
---|
508 | return eng->undefinedValue();
|
---|
509 | return r7;
|
---|
510 | }
|
---|
511 |
|
---|
512 | QScriptValueImpl Array::method_push(QScriptContextPrivate *context,
|
---|
513 | QScriptEnginePrivate *eng,
|
---|
514 | QScriptClassInfo *classInfo)
|
---|
515 | {
|
---|
516 | QScriptValueImpl self = context->thisObject();
|
---|
517 | if (Instance *instance = Instance::get(self, classInfo)) {
|
---|
518 | uint pos = instance->value.size();
|
---|
519 | for (int i = 0; i < context->argumentCount(); ++i) {
|
---|
520 | QScriptValueImpl val = context->argument(i);
|
---|
521 | if (pos == 0xFFFFFFFF) {
|
---|
522 | self.setProperty(pos++, val);
|
---|
523 | self.setProperty(eng->idTable()->id_length, 0);
|
---|
524 | } else {
|
---|
525 | instance->value.assign(pos++, val);
|
---|
526 | }
|
---|
527 | }
|
---|
528 | return QScriptValueImpl(pos);
|
---|
529 | }
|
---|
530 |
|
---|
531 | QScriptNameIdImpl *id_length = eng->idTable()->id_length;
|
---|
532 | QScriptValueImpl r1 = self.property(id_length);
|
---|
533 | quint32 n = r1.toUInt32();
|
---|
534 | for (int index = 0; index < context->argumentCount(); ++index, ++n) {
|
---|
535 | QScriptValueImpl r3 = context->argument(index);
|
---|
536 | QScriptNameIdImpl *name = eng->nameId(QScriptValueImpl(n).toString());
|
---|
537 | self.setProperty(name, r3);
|
---|
538 | }
|
---|
539 | QScriptValueImpl r(n);
|
---|
540 | self.setProperty(id_length, r);
|
---|
541 | return r;
|
---|
542 | }
|
---|
543 |
|
---|
544 | QScriptValueImpl Array::method_reverse(QScriptContextPrivate *context,
|
---|
545 | QScriptEnginePrivate *eng,
|
---|
546 | QScriptClassInfo *classInfo)
|
---|
547 | {
|
---|
548 | QScriptValueImpl self = context->thisObject();
|
---|
549 | if (Instance *instance = Instance::get(self, classInfo)) {
|
---|
550 | int lo = 0, hi = instance->value.count () - 1;
|
---|
551 |
|
---|
552 | for (; lo < hi; ++lo, --hi) {
|
---|
553 | QScriptValueImpl tmp = instance->value.at(lo);
|
---|
554 | instance->value.assign(lo, instance->value.at(hi));
|
---|
555 | instance->value.assign(hi, tmp);
|
---|
556 | }
|
---|
557 |
|
---|
558 | } else {
|
---|
559 | QScriptNameIdImpl *id_length = eng->idTable()->id_length;
|
---|
560 |
|
---|
561 | QScriptValueImpl lengthValue = self.property(id_length);
|
---|
562 | quint32 length = 0;
|
---|
563 | if (lengthValue.isValid())
|
---|
564 | length = QScriptEnginePrivate::toUint32(lengthValue.toNumber());
|
---|
565 | const quint32 m = length / 2;
|
---|
566 | for (quint32 i = 0; i < m; ++i) {
|
---|
567 | quint32 j = length - i - 1;
|
---|
568 |
|
---|
569 | QScriptNameIdImpl *iid = eng->nameId(QScriptValueImpl(i).toString());
|
---|
570 | QScriptNameIdImpl *jid = eng->nameId(QScriptValueImpl(j).toString());
|
---|
571 |
|
---|
572 | QScript::Member imember;
|
---|
573 | QScriptValueImpl ibase;
|
---|
574 | QScriptValueImpl ival;
|
---|
575 | bool iok = self.resolve(iid, &imember, &ibase, QScriptValue::ResolvePrototype, QScript::ReadWrite);
|
---|
576 | if (iok)
|
---|
577 | ibase.get(iid, &ival);
|
---|
578 | else
|
---|
579 | ival = eng->undefinedValue();
|
---|
580 |
|
---|
581 | QScript::Member jmember;
|
---|
582 | QScriptValueImpl jbase;
|
---|
583 | QScriptValueImpl jval;
|
---|
584 | bool jok = self.resolve(jid, &jmember, &jbase, QScriptValue::ResolvePrototype, QScript::ReadWrite);
|
---|
585 | if (jok)
|
---|
586 | jbase.get(jid, &jval);
|
---|
587 | else
|
---|
588 | jval = eng->undefinedValue();
|
---|
589 |
|
---|
590 | if (!jok) {
|
---|
591 | if (iok) {
|
---|
592 | if (eng->strictlyEquals(ibase, self))
|
---|
593 | ibase.removeMember(imember);
|
---|
594 | self.setProperty(jid, ival);
|
---|
595 | }
|
---|
596 | } else if (!iok) {
|
---|
597 | self.setProperty(iid, jval);
|
---|
598 | if (eng->strictlyEquals(jbase, self))
|
---|
599 | jbase.removeMember(jmember);
|
---|
600 | } else {
|
---|
601 | if (eng->strictlyEquals(self, ibase))
|
---|
602 | self.put(imember, jval);
|
---|
603 | else
|
---|
604 | self.setProperty(iid, jval);
|
---|
605 | if (eng->strictlyEquals(self, jbase))
|
---|
606 | self.put(jmember, ival);
|
---|
607 | else
|
---|
608 | self.setProperty(jid, ival);
|
---|
609 | }
|
---|
610 | }
|
---|
611 | }
|
---|
612 |
|
---|
613 | return context->thisObject();
|
---|
614 | }
|
---|
615 |
|
---|
616 | QScriptValueImpl Array::method_shift(QScriptContextPrivate *context,
|
---|
617 | QScriptEnginePrivate *eng,
|
---|
618 | QScriptClassInfo *)
|
---|
619 | {
|
---|
620 | QScriptNameIdImpl *id_length = eng->idTable()->id_length;
|
---|
621 |
|
---|
622 | QScriptValueImpl self = context->thisObject();
|
---|
623 | quint32 length = self.property(id_length).toUInt32();
|
---|
624 | if (length == 0) {
|
---|
625 | self.setProperty(id_length, QScriptValueImpl(0));
|
---|
626 | return eng->undefinedValue();
|
---|
627 | }
|
---|
628 |
|
---|
629 | QScript::Member member;
|
---|
630 | QScriptValueImpl base;
|
---|
631 |
|
---|
632 | QScriptValueImpl result = self.property(QLatin1String("0"));
|
---|
633 | if (! result.isValid())
|
---|
634 | result = eng->undefinedValue();
|
---|
635 |
|
---|
636 | for (quint32 index = 1; index < length; ++index) {
|
---|
637 | QScriptNameIdImpl *k = eng->nameId(QScriptValueImpl(index).toString());
|
---|
638 | QScriptNameIdImpl *k1 = eng->nameId(QScriptValueImpl(index - 1).toString());
|
---|
639 |
|
---|
640 | QScriptValueImpl v = self.property(k);
|
---|
641 | QScriptValueImpl v1 = self.property(k1);
|
---|
642 |
|
---|
643 | if (v.isValid())
|
---|
644 | self.setProperty(k1, v);
|
---|
645 |
|
---|
646 | else if (v1.isValid() && self.resolve(k1, &member, &base, QScriptValue::ResolveLocal, QScript::ReadWrite))
|
---|
647 | self.removeMember(member);
|
---|
648 | }
|
---|
649 |
|
---|
650 | QScriptValueImpl len = QScriptValueImpl(length - 1);
|
---|
651 |
|
---|
652 | if (self.resolve(eng->nameId(len.toString()), &member, &base, QScriptValue::ResolveLocal, QScript::ReadWrite))
|
---|
653 | self.removeMember(member);
|
---|
654 |
|
---|
655 | self.setProperty(id_length, len);
|
---|
656 | return (result);
|
---|
657 | }
|
---|
658 |
|
---|
659 | QScriptValueImpl Array::method_slice(QScriptContextPrivate *context,
|
---|
660 | QScriptEnginePrivate *eng,
|
---|
661 | QScriptClassInfo *)
|
---|
662 | {
|
---|
663 | QScript::Array result(eng);
|
---|
664 |
|
---|
665 | QScriptValueImpl start = context->argument(0);
|
---|
666 | QScriptValueImpl end = context->argument(1);
|
---|
667 |
|
---|
668 | QScriptValueImpl self = context->thisObject();
|
---|
669 | QScriptNameIdImpl *id_length = eng->idTable()->id_length;
|
---|
670 | qsreal r2 = self.property(id_length).toNumber();
|
---|
671 | quint32 r3 = QScriptEnginePrivate::toUint32(r2);
|
---|
672 | qint32 r4 = qint32 (start.toInteger());
|
---|
673 | quint32 r5 = r4 < 0 ? qMax(quint32(r3 + r4), quint32(0)) : qMin(quint32(r4), r3);
|
---|
674 | quint32 k = r5;
|
---|
675 | qint32 r7 = end.isUndefined() ? r3 : qint32 (end.toInteger());
|
---|
676 | quint32 r8 = r7 < 0 ? qMax(quint32(r3 + r7), quint32(0)) : qMin(quint32(r7), r3);
|
---|
677 | quint32 n = 0;
|
---|
678 | for (; k < r8; ++k) {
|
---|
679 | QString r11 = QScriptValueImpl(k).toString();
|
---|
680 | QScriptValueImpl v = self.property(r11);
|
---|
681 | if (v.isValid())
|
---|
682 | result.assign(n++, v);
|
---|
683 | }
|
---|
684 | return eng->newArray(result);
|
---|
685 | }
|
---|
686 |
|
---|
687 | QScriptValueImpl Array::method_sort(QScriptContextPrivate *context,
|
---|
688 | QScriptEnginePrivate *,
|
---|
689 | QScriptClassInfo *classInfo)
|
---|
690 | {
|
---|
691 | QScriptValueImpl self = context->thisObject();
|
---|
692 | QScriptValueImpl comparefn = context->argument(0);
|
---|
693 | if (Instance *instance = Instance::get(self, classInfo)) {
|
---|
694 | instance->value.sort(comparefn);
|
---|
695 | return context->thisObject();
|
---|
696 | }
|
---|
697 | return context->throwNotImplemented(QLatin1String("Array.prototype.sort"));
|
---|
698 | }
|
---|
699 |
|
---|
700 | QScriptValueImpl Array::method_splice(QScriptContextPrivate *context,
|
---|
701 | QScriptEnginePrivate *eng,
|
---|
702 | QScriptClassInfo *classInfo)
|
---|
703 | {
|
---|
704 | if (context->argumentCount() < 2)
|
---|
705 | return eng->undefinedValue();
|
---|
706 |
|
---|
707 | QScriptValueImpl self = context->thisObject();
|
---|
708 |
|
---|
709 | qsreal start = context->argument(0).toInteger();
|
---|
710 | qsreal deleteCount = context->argument(1).toInteger();
|
---|
711 |
|
---|
712 | QScriptValueImpl arrayCtor = eng->globalObject().property(QLatin1String("Array"));
|
---|
713 | QScriptValueImpl a = arrayCtor.construct();
|
---|
714 |
|
---|
715 | if (Instance *instance = Instance::get(self, classInfo)) {
|
---|
716 | QVector<QScriptValueImpl> items;
|
---|
717 | for (int i = 2; i < context->argumentCount(); ++i)
|
---|
718 | items << context->argument(i);
|
---|
719 | Instance *otherInstance = Instance::get(a, classInfo);
|
---|
720 | Q_ASSERT(otherInstance);
|
---|
721 | instance->value.splice(start, deleteCount, items, otherInstance->value);
|
---|
722 | return a;
|
---|
723 | }
|
---|
724 |
|
---|
725 | return context->throwNotImplemented(QLatin1String("Array.prototype.splice"));
|
---|
726 | }
|
---|
727 |
|
---|
728 | QScriptValueImpl Array::method_unshift(QScriptContextPrivate *context,
|
---|
729 | QScriptEnginePrivate *eng,
|
---|
730 | QScriptClassInfo *)
|
---|
731 | {
|
---|
732 | QScriptValueImpl self = context->thisObject();
|
---|
733 |
|
---|
734 | QScriptNameIdImpl *id_length = eng->idTable()->id_length;
|
---|
735 | QScriptValueImpl r1 = self.property(id_length);
|
---|
736 | quint32 r2 = r1.isValid() ? QScriptEnginePrivate::toUint32(r1.toNumber()) : 0;
|
---|
737 | quint32 r3 = quint32 (context->argumentCount());
|
---|
738 | quint32 k = r2;
|
---|
739 | for (; k != 0; --k) {
|
---|
740 | QScriptNameIdImpl *r6 = eng->nameId(QScriptValueImpl(k - 1).toString());
|
---|
741 | QScriptNameIdImpl *r7 = eng->nameId(QScriptValueImpl(k + r3 - 1).toString());
|
---|
742 | QScriptValueImpl r8 = self.property(r6);
|
---|
743 | if (r8.isValid())
|
---|
744 | self.setProperty(r7, r8);
|
---|
745 |
|
---|
746 | else {
|
---|
747 | QScript::Member member;
|
---|
748 | QScriptValueImpl base;
|
---|
749 |
|
---|
750 | if (self.resolve(r7, &member, &base, QScriptValue::ResolveLocal, QScript::ReadWrite))
|
---|
751 | self.removeMember(member);
|
---|
752 | }
|
---|
753 | }
|
---|
754 |
|
---|
755 | for (k = 0; k < r3; ++k) {
|
---|
756 | QScriptValueImpl r16 = context->argument(k);
|
---|
757 | QScriptNameIdImpl *r17 = eng->nameId(QScriptValueImpl(k).toString());
|
---|
758 | self.setProperty(r17, r16);
|
---|
759 | }
|
---|
760 | QScriptValueImpl r(r2 + r3);
|
---|
761 | self.setProperty(id_length, r);
|
---|
762 | return (r);
|
---|
763 | }
|
---|
764 |
|
---|
765 | Array::Instance *Array::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass)
|
---|
766 | {
|
---|
767 | if (! klass || klass == object.classInfo())
|
---|
768 | return static_cast<Instance*> (object.objectData());
|
---|
769 |
|
---|
770 | return 0;
|
---|
771 | }
|
---|
772 |
|
---|
773 | } } // namespace QScript::Ecma
|
---|
774 |
|
---|
775 | QT_END_NAMESPACE
|
---|
776 |
|
---|
777 | #endif // QT_NO_SCRIPT
|
---|