|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtDeclarative module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "private/qdeclarativecompiler_p.h" |
|
43 |
|
44 #include "private/qdeclarativecompositetypedata_p.h" |
|
45 #include "private/qdeclarativeparser_p.h" |
|
46 #include "private/qdeclarativescriptparser_p.h" |
|
47 #include "qdeclarativepropertyvaluesource.h" |
|
48 #include "qdeclarativecomponent.h" |
|
49 #include "private/qmetaobjectbuilder_p.h" |
|
50 #include "private/qdeclarativestringconverters_p.h" |
|
51 #include "private/qdeclarativeengine_p.h" |
|
52 #include "qdeclarativeengine.h" |
|
53 #include "qdeclarativecontext.h" |
|
54 #include "private/qdeclarativemetatype_p.h" |
|
55 #include "private/qdeclarativecustomparser_p_p.h" |
|
56 #include "private/qdeclarativecontext_p.h" |
|
57 #include "private/qdeclarativecomponent_p.h" |
|
58 #include "parser/qdeclarativejsast_p.h" |
|
59 #include "private/qdeclarativevmemetaobject_p.h" |
|
60 #include "private/qdeclarativeexpression_p.h" |
|
61 #include "private/qdeclarativeproperty_p.h" |
|
62 #include "private/qdeclarativerewrite_p.h" |
|
63 #include "qdeclarativescriptstring.h" |
|
64 #include "private/qdeclarativeglobal_p.h" |
|
65 #include "private/qdeclarativescriptparser_p.h" |
|
66 #include "private/qdeclarativebinding_p.h" |
|
67 #include "private/qdeclarativecompiledbindings_p.h" |
|
68 #include "private/qdeclarativeglobalscriptclass_p.h" |
|
69 |
|
70 #include <QColor> |
|
71 #include <QDebug> |
|
72 #include <QPointF> |
|
73 #include <QSizeF> |
|
74 #include <QRectF> |
|
75 #include <QAtomicInt> |
|
76 #include <QtCore/qdebug.h> |
|
77 #include <QtCore/qdatetime.h> |
|
78 |
|
79 QT_BEGIN_NAMESPACE |
|
80 |
|
81 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); |
|
82 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS); |
|
83 DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP); |
|
84 |
|
85 using namespace QDeclarativeParser; |
|
86 |
|
87 /*! |
|
88 Instantiate a new QDeclarativeCompiler. |
|
89 */ |
|
90 QDeclarativeCompiler::QDeclarativeCompiler() |
|
91 : output(0), engine(0), unitRoot(0), unit(0) |
|
92 { |
|
93 } |
|
94 |
|
95 /*! |
|
96 Returns true if the last call to compile() caused errors. |
|
97 |
|
98 \sa errors() |
|
99 */ |
|
100 bool QDeclarativeCompiler::isError() const |
|
101 { |
|
102 return !exceptions.isEmpty(); |
|
103 } |
|
104 |
|
105 /*! |
|
106 Return the list of errors from the last call to compile(), or an empty list |
|
107 if there were no errors. |
|
108 */ |
|
109 QList<QDeclarativeError> QDeclarativeCompiler::errors() const |
|
110 { |
|
111 return exceptions; |
|
112 } |
|
113 |
|
114 /*! |
|
115 Returns true if \a name refers to an attached property, false otherwise. |
|
116 |
|
117 Attached property names are those that start with a capital letter. |
|
118 */ |
|
119 bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name) |
|
120 { |
|
121 return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z'; |
|
122 } |
|
123 |
|
124 /*! |
|
125 Returns true if \a name refers to a signal property, false otherwise. |
|
126 |
|
127 Signal property names are those that start with "on", followed by a capital |
|
128 letter. |
|
129 */ |
|
130 bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name) |
|
131 { |
|
132 return name.length() >= 3 && name.startsWith("on") && |
|
133 'A' <= name.at(2) && 'Z' >= name.at(2); |
|
134 } |
|
135 |
|
136 /*! |
|
137 \macro COMPILE_EXCEPTION |
|
138 \internal |
|
139 Inserts an error into the QDeclarativeCompiler error list, and returns false |
|
140 (failure). |
|
141 |
|
142 \a token is used to source the error line and column, and \a desc is the |
|
143 error itself. \a desc can be an expression that can be piped into QDebug. |
|
144 |
|
145 For example: |
|
146 |
|
147 \code |
|
148 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name))); |
|
149 \endcode |
|
150 */ |
|
151 #define COMPILE_EXCEPTION(token, desc) \ |
|
152 { \ |
|
153 QString exceptionDescription; \ |
|
154 QDeclarativeError error; \ |
|
155 error.setUrl(output->url); \ |
|
156 error.setLine((token)->location.start.line); \ |
|
157 error.setColumn((token)->location.start.column); \ |
|
158 error.setDescription(desc.trimmed()); \ |
|
159 exceptions << error; \ |
|
160 return false; \ |
|
161 } |
|
162 |
|
163 /*! |
|
164 \macro COMPILE_CHECK |
|
165 \internal |
|
166 Returns false if \a is false, otherwise does nothing. |
|
167 */ |
|
168 #define COMPILE_CHECK(a) \ |
|
169 { \ |
|
170 if (!a) return false; \ |
|
171 } |
|
172 |
|
173 /*! |
|
174 Returns true if literal \a v can be assigned to property \a prop, otherwise |
|
175 false. |
|
176 |
|
177 This test corresponds to action taken by genLiteralAssignment(). Any change |
|
178 made here, must have a corresponding action in genLiteralAssigment(). |
|
179 */ |
|
180 bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop, |
|
181 QDeclarativeParser::Value *v) |
|
182 { |
|
183 QString string = v->value.asString(); |
|
184 |
|
185 if (!prop.isWritable()) |
|
186 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name()))); |
|
187 |
|
188 if (prop.isEnumType()) { |
|
189 int value; |
|
190 if (prop.isFlagType()) { |
|
191 value = prop.enumerator().keysToValue(string.toUtf8().constData()); |
|
192 } else |
|
193 value = prop.enumerator().keyToValue(string.toUtf8().constData()); |
|
194 if (value == -1) |
|
195 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration")); |
|
196 return true; |
|
197 } |
|
198 int type = prop.userType(); |
|
199 switch(type) { |
|
200 case -1: |
|
201 break; |
|
202 case QVariant::String: |
|
203 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected")); |
|
204 break; |
|
205 case QVariant::Url: |
|
206 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected")); |
|
207 break; |
|
208 case QVariant::UInt: |
|
209 { |
|
210 bool ok = v->value.isNumber(); |
|
211 if (ok) { |
|
212 double n = v->value.asNumber(); |
|
213 if (double(uint(n)) != n) |
|
214 ok = false; |
|
215 } |
|
216 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected")); |
|
217 } |
|
218 break; |
|
219 case QVariant::Int: |
|
220 { |
|
221 bool ok = v->value.isNumber(); |
|
222 if (ok) { |
|
223 double n = v->value.asNumber(); |
|
224 if (double(int(n)) != n) |
|
225 ok = false; |
|
226 } |
|
227 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected")); |
|
228 } |
|
229 break; |
|
230 case QMetaType::Float: |
|
231 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: float expected")); |
|
232 break; |
|
233 case QVariant::Double: |
|
234 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: double expected")); |
|
235 break; |
|
236 case QVariant::Color: |
|
237 { |
|
238 bool ok; |
|
239 QDeclarativeStringConverters::colorFromString(string, &ok); |
|
240 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected")); |
|
241 } |
|
242 break; |
|
243 case QVariant::Date: |
|
244 { |
|
245 bool ok; |
|
246 QDeclarativeStringConverters::dateFromString(string, &ok); |
|
247 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected")); |
|
248 } |
|
249 break; |
|
250 case QVariant::Time: |
|
251 { |
|
252 bool ok; |
|
253 QDeclarativeStringConverters::timeFromString(string, &ok); |
|
254 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected")); |
|
255 } |
|
256 break; |
|
257 case QVariant::DateTime: |
|
258 { |
|
259 bool ok; |
|
260 QDeclarativeStringConverters::dateTimeFromString(string, &ok); |
|
261 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected")); |
|
262 } |
|
263 break; |
|
264 case QVariant::Point: |
|
265 case QVariant::PointF: |
|
266 { |
|
267 bool ok; |
|
268 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok); |
|
269 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected")); |
|
270 } |
|
271 break; |
|
272 case QVariant::Size: |
|
273 case QVariant::SizeF: |
|
274 { |
|
275 bool ok; |
|
276 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok); |
|
277 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected")); |
|
278 } |
|
279 break; |
|
280 case QVariant::Rect: |
|
281 case QVariant::RectF: |
|
282 { |
|
283 bool ok; |
|
284 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok); |
|
285 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected")); |
|
286 } |
|
287 break; |
|
288 case QVariant::Bool: |
|
289 { |
|
290 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected")); |
|
291 } |
|
292 break; |
|
293 case QVariant::Vector3D: |
|
294 { |
|
295 bool ok; |
|
296 QDeclarativeStringConverters::vector3DFromString(string, &ok); |
|
297 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected")); |
|
298 } |
|
299 break; |
|
300 default: |
|
301 { |
|
302 int t = prop.userType(); |
|
303 QDeclarativeMetaType::StringConverter converter = |
|
304 QDeclarativeMetaType::customStringConverter(t); |
|
305 if (!converter) |
|
306 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type())))); |
|
307 } |
|
308 break; |
|
309 } |
|
310 return true; |
|
311 } |
|
312 |
|
313 /*! |
|
314 Generate a store instruction for assigning literal \a v to property \a prop. |
|
315 |
|
316 Any literal assignment that is approved in testLiteralAssignment() must have |
|
317 a corresponding action in this method. |
|
318 */ |
|
319 void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop, |
|
320 QDeclarativeParser::Value *v) |
|
321 { |
|
322 QString string = v->value.asString(); |
|
323 |
|
324 QDeclarativeInstruction instr; |
|
325 instr.line = v->location.start.line; |
|
326 if (prop.isEnumType()) { |
|
327 int value; |
|
328 if (prop.isFlagType()) { |
|
329 value = prop.enumerator().keysToValue(string.toUtf8().constData()); |
|
330 } else |
|
331 value = prop.enumerator().keyToValue(string.toUtf8().constData()); |
|
332 |
|
333 instr.type = QDeclarativeInstruction::StoreInteger; |
|
334 instr.storeInteger.propertyIndex = prop.propertyIndex(); |
|
335 instr.storeInteger.value = value; |
|
336 output->bytecode << instr; |
|
337 return; |
|
338 } |
|
339 |
|
340 int type = prop.userType(); |
|
341 switch(type) { |
|
342 case -1: |
|
343 { |
|
344 if (v->value.isNumber()) { |
|
345 double n = v->value.asNumber(); |
|
346 if (double(int(n)) == n) { |
|
347 instr.type = QDeclarativeInstruction::StoreVariantInteger; |
|
348 instr.storeInteger.propertyIndex = prop.propertyIndex(); |
|
349 instr.storeInteger.value = int(n); |
|
350 } else { |
|
351 instr.type = QDeclarativeInstruction::StoreVariantDouble; |
|
352 instr.storeDouble.propertyIndex = prop.propertyIndex(); |
|
353 instr.storeDouble.value = n; |
|
354 } |
|
355 } else if(v->value.isBoolean()) { |
|
356 instr.type = QDeclarativeInstruction::StoreVariantBool; |
|
357 instr.storeBool.propertyIndex = prop.propertyIndex(); |
|
358 instr.storeBool.value = v->value.asBoolean(); |
|
359 } else { |
|
360 instr.type = QDeclarativeInstruction::StoreVariant; |
|
361 instr.storeString.propertyIndex = prop.propertyIndex(); |
|
362 instr.storeString.value = output->indexForString(string); |
|
363 } |
|
364 } |
|
365 break; |
|
366 case QVariant::String: |
|
367 { |
|
368 instr.type = QDeclarativeInstruction::StoreString; |
|
369 instr.storeString.propertyIndex = prop.propertyIndex(); |
|
370 instr.storeString.value = output->indexForString(string); |
|
371 } |
|
372 break; |
|
373 case QVariant::Url: |
|
374 { |
|
375 instr.type = QDeclarativeInstruction::StoreUrl; |
|
376 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string)); |
|
377 instr.storeUrl.propertyIndex = prop.propertyIndex(); |
|
378 instr.storeUrl.value = output->indexForUrl(u); |
|
379 } |
|
380 break; |
|
381 case QVariant::UInt: |
|
382 { |
|
383 instr.type = QDeclarativeInstruction::StoreInteger; |
|
384 instr.storeInteger.propertyIndex = prop.propertyIndex(); |
|
385 instr.storeInteger.value = uint(v->value.asNumber()); |
|
386 } |
|
387 break; |
|
388 case QVariant::Int: |
|
389 { |
|
390 instr.type = QDeclarativeInstruction::StoreInteger; |
|
391 instr.storeInteger.propertyIndex = prop.propertyIndex(); |
|
392 instr.storeInteger.value = int(v->value.asNumber()); |
|
393 } |
|
394 break; |
|
395 case QMetaType::Float: |
|
396 { |
|
397 instr.type = QDeclarativeInstruction::StoreFloat; |
|
398 instr.storeFloat.propertyIndex = prop.propertyIndex(); |
|
399 instr.storeFloat.value = float(v->value.asNumber()); |
|
400 } |
|
401 break; |
|
402 case QVariant::Double: |
|
403 { |
|
404 instr.type = QDeclarativeInstruction::StoreDouble; |
|
405 instr.storeDouble.propertyIndex = prop.propertyIndex(); |
|
406 instr.storeDouble.value = v->value.asNumber(); |
|
407 } |
|
408 break; |
|
409 case QVariant::Color: |
|
410 { |
|
411 QColor c = QDeclarativeStringConverters::colorFromString(string); |
|
412 instr.type = QDeclarativeInstruction::StoreColor; |
|
413 instr.storeColor.propertyIndex = prop.propertyIndex(); |
|
414 instr.storeColor.value = c.rgba(); |
|
415 } |
|
416 break; |
|
417 case QVariant::Date: |
|
418 { |
|
419 QDate d = QDeclarativeStringConverters::dateFromString(string); |
|
420 instr.type = QDeclarativeInstruction::StoreDate; |
|
421 instr.storeDate.propertyIndex = prop.propertyIndex(); |
|
422 instr.storeDate.value = d.toJulianDay(); |
|
423 } |
|
424 break; |
|
425 case QVariant::Time: |
|
426 { |
|
427 QTime time = QDeclarativeStringConverters::timeFromString(string); |
|
428 int data[] = { time.hour(), time.minute(), |
|
429 time.second(), time.msec() }; |
|
430 int index = output->indexForInt(data, 4); |
|
431 instr.type = QDeclarativeInstruction::StoreTime; |
|
432 instr.storeTime.propertyIndex = prop.propertyIndex(); |
|
433 instr.storeTime.valueIndex = index; |
|
434 } |
|
435 break; |
|
436 case QVariant::DateTime: |
|
437 { |
|
438 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string); |
|
439 int data[] = { dateTime.date().toJulianDay(), |
|
440 dateTime.time().hour(), |
|
441 dateTime.time().minute(), |
|
442 dateTime.time().second(), |
|
443 dateTime.time().msec() }; |
|
444 int index = output->indexForInt(data, 5); |
|
445 instr.type = QDeclarativeInstruction::StoreDateTime; |
|
446 instr.storeDateTime.propertyIndex = prop.propertyIndex(); |
|
447 instr.storeDateTime.valueIndex = index; |
|
448 } |
|
449 break; |
|
450 case QVariant::Point: |
|
451 case QVariant::PointF: |
|
452 { |
|
453 bool ok; |
|
454 QPointF point = |
|
455 QDeclarativeStringConverters::pointFFromString(string, &ok); |
|
456 float data[] = { float(point.x()), float(point.y()) }; |
|
457 int index = output->indexForFloat(data, 2); |
|
458 if (type == QVariant::PointF) |
|
459 instr.type = QDeclarativeInstruction::StorePointF; |
|
460 else |
|
461 instr.type = QDeclarativeInstruction::StorePoint; |
|
462 instr.storeRealPair.propertyIndex = prop.propertyIndex(); |
|
463 instr.storeRealPair.valueIndex = index; |
|
464 } |
|
465 break; |
|
466 case QVariant::Size: |
|
467 case QVariant::SizeF: |
|
468 { |
|
469 bool ok; |
|
470 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok); |
|
471 float data[] = { float(size.width()), float(size.height()) }; |
|
472 int index = output->indexForFloat(data, 2); |
|
473 if (type == QVariant::SizeF) |
|
474 instr.type = QDeclarativeInstruction::StoreSizeF; |
|
475 else |
|
476 instr.type = QDeclarativeInstruction::StoreSize; |
|
477 instr.storeRealPair.propertyIndex = prop.propertyIndex(); |
|
478 instr.storeRealPair.valueIndex = index; |
|
479 } |
|
480 break; |
|
481 case QVariant::Rect: |
|
482 case QVariant::RectF: |
|
483 { |
|
484 bool ok; |
|
485 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok); |
|
486 float data[] = { float(rect.x()), float(rect.y()), |
|
487 float(rect.width()), float(rect.height()) }; |
|
488 int index = output->indexForFloat(data, 4); |
|
489 if (type == QVariant::RectF) |
|
490 instr.type = QDeclarativeInstruction::StoreRectF; |
|
491 else |
|
492 instr.type = QDeclarativeInstruction::StoreRect; |
|
493 instr.storeRect.propertyIndex = prop.propertyIndex(); |
|
494 instr.storeRect.valueIndex = index; |
|
495 } |
|
496 break; |
|
497 case QVariant::Bool: |
|
498 { |
|
499 bool b = v->value.asBoolean(); |
|
500 instr.type = QDeclarativeInstruction::StoreBool; |
|
501 instr.storeBool.propertyIndex = prop.propertyIndex(); |
|
502 instr.storeBool.value = b; |
|
503 } |
|
504 break; |
|
505 case QVariant::Vector3D: |
|
506 { |
|
507 bool ok; |
|
508 QVector3D vector = |
|
509 QDeclarativeStringConverters::vector3DFromString(string, &ok); |
|
510 float data[] = { float(vector.x()), float(vector.y()), float(vector.z()) }; |
|
511 int index = output->indexForFloat(data, 3); |
|
512 instr.type = QDeclarativeInstruction::StoreVector3D; |
|
513 instr.storeRealPair.propertyIndex = prop.propertyIndex(); |
|
514 instr.storeRealPair.valueIndex = index; |
|
515 } |
|
516 break; |
|
517 default: |
|
518 { |
|
519 int t = prop.userType(); |
|
520 int index = output->customTypeData.count(); |
|
521 instr.type = QDeclarativeInstruction::AssignCustomType; |
|
522 instr.assignCustomType.propertyIndex = prop.propertyIndex(); |
|
523 instr.assignCustomType.valueIndex = index; |
|
524 |
|
525 QDeclarativeCompiledData::CustomTypeData data; |
|
526 data.index = output->indexForString(string); |
|
527 data.type = t; |
|
528 output->customTypeData << data; |
|
529 } |
|
530 break; |
|
531 } |
|
532 output->bytecode << instr; |
|
533 } |
|
534 |
|
535 /*! |
|
536 Resets data by clearing the lists that the QDeclarativeCompiler modifies. |
|
537 */ |
|
538 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data) |
|
539 { |
|
540 data->types.clear(); |
|
541 data->primitives.clear(); |
|
542 data->floatData.clear(); |
|
543 data->intData.clear(); |
|
544 data->customTypeData.clear(); |
|
545 data->datas.clear(); |
|
546 data->bytecode.clear(); |
|
547 } |
|
548 |
|
549 /*! |
|
550 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine |
|
551 with which the QDeclarativeCompiledData will be associated. |
|
552 |
|
553 Returns true on success, false on failure. On failure, the compile errors |
|
554 are available from errors(). |
|
555 |
|
556 If the environment variant QML_COMPILER_DUMP is set |
|
557 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr |
|
558 on a successful compiler. |
|
559 */ |
|
560 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine, |
|
561 QDeclarativeCompositeTypeData *unit, |
|
562 QDeclarativeCompiledData *out) |
|
563 { |
|
564 exceptions.clear(); |
|
565 |
|
566 Q_ASSERT(out); |
|
567 reset(out); |
|
568 |
|
569 output = out; |
|
570 |
|
571 // Compile types |
|
572 for (int ii = 0; ii < unit->types.count(); ++ii) { |
|
573 QDeclarativeCompositeTypeData::TypeReference &tref = unit->types[ii]; |
|
574 QDeclarativeCompiledData::TypeReference ref; |
|
575 QDeclarativeScriptParser::TypeReference *parserRef = unit->data.referencedTypes().at(ii); |
|
576 if (tref.type) { |
|
577 ref.type = tref.type; |
|
578 if (!ref.type->isCreatable()) { |
|
579 QString err = ref.type->noCreationReason(); |
|
580 if (err.isEmpty()) |
|
581 err = tr( "Element is not creatable."); |
|
582 COMPILE_EXCEPTION(parserRef->refObjects.first(), err); |
|
583 } |
|
584 } else if (tref.unit) { |
|
585 ref.component = tref.unit->toComponent(engine); |
|
586 |
|
587 if (ref.component->isError()) { |
|
588 QDeclarativeError error; |
|
589 error.setUrl(output->url); |
|
590 error.setDescription(QLatin1String("Unable to create type ") + |
|
591 parserRef->name); |
|
592 if (!parserRef->refObjects.isEmpty()) { |
|
593 QDeclarativeParser::Object *parserObject = parserRef->refObjects.first(); |
|
594 error.setLine(parserObject->location.start.line); |
|
595 error.setColumn(parserObject->location.start.column); |
|
596 } |
|
597 |
|
598 exceptions << error; |
|
599 exceptions << ref.component->errors(); |
|
600 reset(out); |
|
601 return false; |
|
602 } |
|
603 ref.ref = tref.unit; |
|
604 ref.ref->addref(); |
|
605 } |
|
606 ref.className = parserRef->name.toUtf8(); |
|
607 out->types << ref; |
|
608 } |
|
609 |
|
610 Object *root = unit->data.tree(); |
|
611 Q_ASSERT(root); |
|
612 |
|
613 this->engine = engine; |
|
614 this->enginePrivate = QDeclarativeEnginePrivate::get(engine); |
|
615 this->unit = unit; |
|
616 this->unitRoot = root; |
|
617 compileTree(root); |
|
618 |
|
619 if (!isError()) { |
|
620 if (compilerDump()) |
|
621 out->dumpInstructions(); |
|
622 if (compilerStatDump()) |
|
623 dumpStats(); |
|
624 } else { |
|
625 reset(out); |
|
626 } |
|
627 |
|
628 compileState = ComponentCompileState(); |
|
629 savedCompileStates.clear(); |
|
630 output = 0; |
|
631 this->engine = 0; |
|
632 this->enginePrivate = 0; |
|
633 this->unit = 0; |
|
634 this->unitRoot = 0; |
|
635 |
|
636 return !isError(); |
|
637 } |
|
638 |
|
639 void QDeclarativeCompiler::compileTree(Object *tree) |
|
640 { |
|
641 compileState.root = tree; |
|
642 componentStat.lineNumber = tree->location.start.line; |
|
643 |
|
644 if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) |
|
645 return; |
|
646 |
|
647 QDeclarativeInstruction init; |
|
648 init.type = QDeclarativeInstruction::Init; |
|
649 init.line = 0; |
|
650 init.init.bindingsSize = compileState.bindings.count(); |
|
651 init.init.parserStatusSize = compileState.parserStatusCount; |
|
652 init.init.contextCache = genContextCache(); |
|
653 if (compileState.compiledBindingData.isEmpty()) |
|
654 init.init.compiledBinding = -1; |
|
655 else |
|
656 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); |
|
657 output->bytecode << init; |
|
658 |
|
659 // Build global import scripts |
|
660 QHash<QString, Object::ScriptBlock> importedScripts; |
|
661 QStringList importedScriptIndexes; |
|
662 |
|
663 for (int ii = 0; ii < unit->scripts.count(); ++ii) { |
|
664 QString scriptCode = QString::fromUtf8(unit->scripts.at(ii).resource->data); |
|
665 Object::ScriptBlock::Pragmas pragmas = QDeclarativeScriptParser::extractPragmas(scriptCode); |
|
666 |
|
667 if (!scriptCode.isEmpty()) { |
|
668 Object::ScriptBlock &scriptBlock = importedScripts[unit->scripts.at(ii).qualifier]; |
|
669 |
|
670 scriptBlock.codes.append(scriptCode); |
|
671 scriptBlock.lineNumbers.append(1); |
|
672 scriptBlock.files.append(unit->scripts.at(ii).resource->url); |
|
673 scriptBlock.pragmas.append(pragmas); |
|
674 } |
|
675 } |
|
676 |
|
677 for (QHash<QString, Object::ScriptBlock>::Iterator iter = importedScripts.begin(); |
|
678 iter != importedScripts.end(); ++iter) { |
|
679 |
|
680 importedScriptIndexes.append(iter.key()); |
|
681 |
|
682 QDeclarativeInstruction import; |
|
683 import.type = QDeclarativeInstruction::StoreImportedScript; |
|
684 import.line = 0; |
|
685 import.storeScript.value = output->scripts.count(); |
|
686 output->scripts << *iter; |
|
687 output->bytecode << import; |
|
688 } |
|
689 |
|
690 genObject(tree); |
|
691 |
|
692 QDeclarativeInstruction def; |
|
693 init.line = 0; |
|
694 def.type = QDeclarativeInstruction::SetDefault; |
|
695 output->bytecode << def; |
|
696 |
|
697 output->importCache = new QDeclarativeTypeNameCache(engine); |
|
698 |
|
699 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii) |
|
700 output->importCache->add(importedScriptIndexes.at(ii), ii); |
|
701 |
|
702 unit->imports.cache(output->importCache, engine); |
|
703 |
|
704 Q_ASSERT(tree->metatype); |
|
705 |
|
706 if (tree->metadata.isEmpty()) { |
|
707 output->root = tree->metatype; |
|
708 } else { |
|
709 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject(); |
|
710 output->root = &output->rootData; |
|
711 } |
|
712 if (!tree->metadata.isEmpty()) |
|
713 enginePrivate->registerCompositeType(output); |
|
714 } |
|
715 |
|
716 static bool ValuePtrLessThan(const Value *t1, const Value *t2) |
|
717 { |
|
718 return t1->location.start.line < t2->location.start.line || |
|
719 (t1->location.start.line == t2->location.start.line && |
|
720 t1->location.start.column < t2->location.start.column); |
|
721 } |
|
722 |
|
723 bool QDeclarativeCompiler::buildObject(Object *obj, const BindingContext &ctxt) |
|
724 { |
|
725 componentStat.objects++; |
|
726 |
|
727 Q_ASSERT (obj->type != -1); |
|
728 const QDeclarativeCompiledData::TypeReference &tr = |
|
729 output->types.at(obj->type); |
|
730 obj->metatype = tr.metaObject(); |
|
731 |
|
732 if (tr.component) |
|
733 obj->url = tr.component->url(); |
|
734 if (tr.type) |
|
735 obj->typeName = tr.type->qmlTypeName(); |
|
736 obj->className = tr.className; |
|
737 |
|
738 // This object is a "Component" element |
|
739 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) { |
|
740 COMPILE_CHECK(buildComponent(obj, ctxt)); |
|
741 return true; |
|
742 } |
|
743 |
|
744 // Object instantiations reset the binding context |
|
745 BindingContext objCtxt(obj); |
|
746 |
|
747 // Create the synthesized meta object, ignoring aliases |
|
748 COMPILE_CHECK(checkDynamicMeta(obj)); |
|
749 COMPILE_CHECK(mergeDynamicMetaProperties(obj)); |
|
750 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases)); |
|
751 |
|
752 // Find the native type and check for the QDeclarativeParserStatus interface |
|
753 QDeclarativeType *type = toQmlType(obj); |
|
754 Q_ASSERT(type); |
|
755 obj->parserStatusCast = type->parserStatusCast(); |
|
756 if (obj->parserStatusCast != -1) |
|
757 compileState.parserStatusCount++; |
|
758 |
|
759 // Check if this is a custom parser type. Custom parser types allow |
|
760 // assignments to non-existent properties. These assignments are then |
|
761 // compiled by the type. |
|
762 bool isCustomParser = output->types.at(obj->type).type && |
|
763 output->types.at(obj->type).type->customParser() != 0; |
|
764 QList<QDeclarativeCustomParserProperty> customProps; |
|
765 |
|
766 // Fetch the list of deferred properties |
|
767 QStringList deferredList = deferredProperties(obj); |
|
768 |
|
769 // Must do id property first. This is to ensure that the id given to any |
|
770 // id reference created matches the order in which the objects are |
|
771 // instantiated |
|
772 foreach(Property *prop, obj->properties) { |
|
773 if (prop->name == "id") { |
|
774 COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); |
|
775 break; |
|
776 } |
|
777 } |
|
778 |
|
779 // Merge |
|
780 Property *defaultProperty = 0; |
|
781 Property *skipProperty = 0; |
|
782 if (obj->defaultProperty) { |
|
783 const QMetaObject *metaObject = obj->metaObject(); |
|
784 Q_ASSERT(metaObject); |
|
785 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject); |
|
786 if (p.name()) { |
|
787 Property *explicitProperty = obj->getProperty(p.name(), false); |
|
788 if (explicitProperty && !explicitProperty->value) { |
|
789 skipProperty = explicitProperty; |
|
790 |
|
791 defaultProperty = new Property; |
|
792 defaultProperty->parent = obj; |
|
793 defaultProperty->isDefault = true; |
|
794 defaultProperty->location = obj->defaultProperty->location; |
|
795 defaultProperty->listValueRange = obj->defaultProperty->listValueRange; |
|
796 defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions; |
|
797 |
|
798 defaultProperty->values = obj->defaultProperty->values; |
|
799 defaultProperty->values += explicitProperty->values; |
|
800 foreach(Value *value, defaultProperty->values) |
|
801 value->addref(); |
|
802 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan); |
|
803 |
|
804 } else { |
|
805 defaultProperty = obj->defaultProperty; |
|
806 defaultProperty->addref(); |
|
807 } |
|
808 } else { |
|
809 defaultProperty = obj->defaultProperty; |
|
810 defaultProperty->addref(); |
|
811 } |
|
812 } |
|
813 |
|
814 // Build all explicit properties specified |
|
815 foreach(Property *prop, obj->properties) { |
|
816 |
|
817 if (prop == skipProperty) |
|
818 continue; |
|
819 if (prop->name == "id") |
|
820 continue; |
|
821 |
|
822 bool canDefer = false; |
|
823 if (isCustomParser) { |
|
824 if (doesPropertyExist(prop, obj)) { |
|
825 int ids = compileState.ids.count(); |
|
826 COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); |
|
827 canDefer = ids == compileState.ids.count(); |
|
828 } else { |
|
829 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop); |
|
830 } |
|
831 } else { |
|
832 if (isSignalPropertyName(prop->name)) { |
|
833 COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); |
|
834 } else { |
|
835 int ids = compileState.ids.count(); |
|
836 COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); |
|
837 canDefer = ids == compileState.ids.count(); |
|
838 } |
|
839 } |
|
840 |
|
841 if (canDefer && !deferredList.isEmpty() && |
|
842 deferredList.contains(QString::fromUtf8(prop->name))) |
|
843 prop->isDeferred = true; |
|
844 |
|
845 } |
|
846 |
|
847 // Build the default property |
|
848 if (defaultProperty) { |
|
849 Property *prop = defaultProperty; |
|
850 |
|
851 bool canDefer = false; |
|
852 if (isCustomParser) { |
|
853 if (doesPropertyExist(prop, obj)) { |
|
854 int ids = compileState.ids.count(); |
|
855 COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); |
|
856 canDefer = ids == compileState.ids.count(); |
|
857 } else { |
|
858 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop); |
|
859 } |
|
860 } else { |
|
861 int ids = compileState.ids.count(); |
|
862 COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); |
|
863 canDefer = ids == compileState.ids.count(); |
|
864 } |
|
865 |
|
866 if (canDefer && !deferredList.isEmpty() && |
|
867 deferredList.contains(QString::fromUtf8(prop->name))) |
|
868 prop->isDeferred = true; |
|
869 } |
|
870 |
|
871 if (defaultProperty) |
|
872 defaultProperty->release(); |
|
873 |
|
874 // Compile custom parser parts |
|
875 if (isCustomParser/* && !customProps.isEmpty()*/) { |
|
876 QDeclarativeCustomParser *cp = output->types.at(obj->type).type->customParser(); |
|
877 cp->clearErrors(); |
|
878 cp->compiler = this; |
|
879 cp->object = obj; |
|
880 obj->custom = cp->compile(customProps); |
|
881 cp->compiler = 0; |
|
882 cp->object = 0; |
|
883 foreach (QDeclarativeError err, cp->errors()) { |
|
884 err.setUrl(output->url); |
|
885 exceptions << err; |
|
886 } |
|
887 } |
|
888 |
|
889 return true; |
|
890 } |
|
891 |
|
892 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) |
|
893 { |
|
894 const QDeclarativeCompiledData::TypeReference &tr = |
|
895 output->types.at(obj->type); |
|
896 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) { |
|
897 genComponent(obj); |
|
898 return; |
|
899 } |
|
900 |
|
901 // Create the object |
|
902 if (obj->custom.isEmpty() && output->types.at(obj->type).type && |
|
903 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) { |
|
904 |
|
905 QDeclarativeInstruction create; |
|
906 create.type = QDeclarativeInstruction::CreateSimpleObject; |
|
907 create.line = obj->location.start.line; |
|
908 create.createSimple.create = output->types.at(obj->type).type->createFunction(); |
|
909 create.createSimple.typeSize = output->types.at(obj->type).type->createSize(); |
|
910 create.createSimple.column = obj->location.start.column; |
|
911 output->bytecode << create; |
|
912 |
|
913 } else { |
|
914 |
|
915 QDeclarativeInstruction create; |
|
916 create.type = QDeclarativeInstruction::CreateObject; |
|
917 create.line = obj->location.start.line; |
|
918 create.create.column = obj->location.start.column; |
|
919 create.create.data = -1; |
|
920 if (!obj->custom.isEmpty()) |
|
921 create.create.data = output->indexForByteArray(obj->custom); |
|
922 create.create.type = obj->type; |
|
923 if (!output->types.at(create.create.type).type && |
|
924 !obj->bindingBitmask.isEmpty()) { |
|
925 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0); |
|
926 create.create.bindingBits = |
|
927 output->indexForByteArray(obj->bindingBitmask); |
|
928 } else { |
|
929 create.create.bindingBits = -1; |
|
930 } |
|
931 output->bytecode << create; |
|
932 |
|
933 } |
|
934 |
|
935 // Setup the synthesized meta object if necessary |
|
936 if (!obj->metadata.isEmpty()) { |
|
937 QDeclarativeInstruction meta; |
|
938 meta.type = QDeclarativeInstruction::StoreMetaObject; |
|
939 meta.line = 0; |
|
940 meta.storeMeta.data = output->indexForByteArray(obj->metadata); |
|
941 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); |
|
942 meta.storeMeta.propertyCache = output->propertyCaches.count(); |
|
943 // ### Surely the creation of this property cache could be more efficient |
|
944 QDeclarativePropertyCache *propertyCache = 0; |
|
945 if (tr.component) |
|
946 propertyCache = QDeclarativeComponentPrivate::get(tr.component)->cc->rootPropertyCache->copy(); |
|
947 else |
|
948 propertyCache = enginePrivate->cache(obj->metaObject()->superClass())->copy(); |
|
949 |
|
950 propertyCache->append(engine, obj->metaObject(), QDeclarativePropertyCache::Data::NoFlags, |
|
951 QDeclarativePropertyCache::Data::IsVMEFunction); |
|
952 |
|
953 if (obj == unitRoot) { |
|
954 propertyCache->addref(); |
|
955 output->rootPropertyCache = propertyCache; |
|
956 } |
|
957 |
|
958 output->propertyCaches << propertyCache; |
|
959 output->bytecode << meta; |
|
960 } else if (obj == unitRoot) { |
|
961 if (tr.component) |
|
962 output->rootPropertyCache = QDeclarativeComponentPrivate::get(tr.component)->cc->rootPropertyCache; |
|
963 else |
|
964 output->rootPropertyCache = enginePrivate->cache(obj->metaObject()); |
|
965 |
|
966 output->rootPropertyCache->addref(); |
|
967 } |
|
968 |
|
969 // Set the object id |
|
970 if (!obj->id.isEmpty()) { |
|
971 QDeclarativeInstruction id; |
|
972 id.type = QDeclarativeInstruction::SetId; |
|
973 id.line = 0; |
|
974 id.setId.value = output->indexForString(obj->id); |
|
975 id.setId.index = obj->idIndex; |
|
976 output->bytecode << id; |
|
977 } |
|
978 |
|
979 // Begin the class |
|
980 if (obj->parserStatusCast != -1) { |
|
981 QDeclarativeInstruction begin; |
|
982 begin.type = QDeclarativeInstruction::BeginObject; |
|
983 begin.begin.castValue = obj->parserStatusCast; |
|
984 begin.line = obj->location.start.line; |
|
985 output->bytecode << begin; |
|
986 } |
|
987 |
|
988 genObjectBody(obj); |
|
989 } |
|
990 |
|
991 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj) |
|
992 { |
|
993 typedef QPair<Property *, int> PropPair; |
|
994 foreach(const PropPair &prop, obj->scriptStringProperties) { |
|
995 QDeclarativeInstruction ss; |
|
996 ss.type = QDeclarativeInstruction::StoreScriptString; |
|
997 ss.storeScriptString.propertyIndex = prop.first->index; |
|
998 ss.storeScriptString.value = |
|
999 output->indexForString(prop.first->values.at(0)->value.asScript()); |
|
1000 ss.storeScriptString.scope = prop.second; |
|
1001 output->bytecode << ss; |
|
1002 } |
|
1003 |
|
1004 bool seenDefer = false; |
|
1005 foreach(Property *prop, obj->valueProperties) { |
|
1006 if (prop->isDeferred) { |
|
1007 seenDefer = true; |
|
1008 continue; |
|
1009 } |
|
1010 genValueProperty(prop, obj); |
|
1011 } |
|
1012 if (seenDefer) { |
|
1013 QDeclarativeInstruction defer; |
|
1014 defer.type = QDeclarativeInstruction::Defer; |
|
1015 defer.line = 0; |
|
1016 defer.defer.deferCount = 0; |
|
1017 int deferIdx = output->bytecode.count(); |
|
1018 output->bytecode << defer; |
|
1019 |
|
1020 QDeclarativeInstruction init; |
|
1021 init.type = QDeclarativeInstruction::Init; |
|
1022 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary |
|
1023 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary |
|
1024 init.init.contextCache = -1; |
|
1025 init.init.compiledBinding = -1; |
|
1026 output->bytecode << init; |
|
1027 |
|
1028 foreach(Property *prop, obj->valueProperties) { |
|
1029 if (!prop->isDeferred) |
|
1030 continue; |
|
1031 genValueProperty(prop, obj); |
|
1032 } |
|
1033 |
|
1034 output->bytecode[deferIdx].defer.deferCount = |
|
1035 output->bytecode.count() - deferIdx - 1; |
|
1036 } |
|
1037 |
|
1038 foreach(Property *prop, obj->signalProperties) { |
|
1039 |
|
1040 QDeclarativeParser::Value *v = prop->values.at(0); |
|
1041 |
|
1042 if (v->type == Value::SignalObject) { |
|
1043 |
|
1044 genObject(v->object); |
|
1045 |
|
1046 QDeclarativeInstruction assign; |
|
1047 assign.type = QDeclarativeInstruction::AssignSignalObject; |
|
1048 assign.line = v->location.start.line; |
|
1049 assign.assignSignalObject.signal = |
|
1050 output->indexForByteArray(prop->name); |
|
1051 output->bytecode << assign; |
|
1052 |
|
1053 } else if (v->type == Value::SignalExpression) { |
|
1054 |
|
1055 BindingContext ctxt = compileState.signalExpressions.value(v); |
|
1056 |
|
1057 QDeclarativeInstruction store; |
|
1058 store.type = QDeclarativeInstruction::StoreSignal; |
|
1059 store.line = v->location.start.line; |
|
1060 store.storeSignal.signalIndex = prop->index; |
|
1061 store.storeSignal.value = |
|
1062 output->indexForString(v->value.asScript().trimmed()); |
|
1063 store.storeSignal.context = ctxt.stack; |
|
1064 output->bytecode << store; |
|
1065 |
|
1066 } |
|
1067 |
|
1068 } |
|
1069 |
|
1070 foreach(Property *prop, obj->attachedProperties) { |
|
1071 QDeclarativeInstruction fetch; |
|
1072 fetch.type = QDeclarativeInstruction::FetchAttached; |
|
1073 fetch.line = prop->location.start.line; |
|
1074 fetch.fetchAttached.id = prop->index; |
|
1075 output->bytecode << fetch; |
|
1076 |
|
1077 genObjectBody(prop->value); |
|
1078 |
|
1079 QDeclarativeInstruction pop; |
|
1080 pop.type = QDeclarativeInstruction::PopFetchedObject; |
|
1081 pop.line = prop->location.start.line; |
|
1082 output->bytecode << pop; |
|
1083 } |
|
1084 |
|
1085 foreach(Property *prop, obj->groupedProperties) { |
|
1086 QDeclarativeInstruction fetch; |
|
1087 fetch.type = QDeclarativeInstruction::FetchObject; |
|
1088 fetch.fetch.property = prop->index; |
|
1089 fetch.line = prop->location.start.line; |
|
1090 output->bytecode << fetch; |
|
1091 |
|
1092 if (!prop->value->metadata.isEmpty()) { |
|
1093 QDeclarativeInstruction meta; |
|
1094 meta.type = QDeclarativeInstruction::StoreMetaObject; |
|
1095 meta.line = 0; |
|
1096 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata); |
|
1097 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata); |
|
1098 meta.storeMeta.propertyCache = output->propertyCaches.count(); |
|
1099 // ### Surely the creation of this property cache could be more efficient |
|
1100 QDeclarativePropertyCache *propertyCache = |
|
1101 enginePrivate->cache(prop->value->metaObject()->superClass())->copy(); |
|
1102 propertyCache->append(engine, prop->value->metaObject(), QDeclarativePropertyCache::Data::NoFlags, |
|
1103 QDeclarativePropertyCache::Data::IsVMEFunction); |
|
1104 |
|
1105 output->propertyCaches << propertyCache; |
|
1106 output->bytecode << meta; |
|
1107 } |
|
1108 |
|
1109 genObjectBody(prop->value); |
|
1110 |
|
1111 QDeclarativeInstruction pop; |
|
1112 pop.type = QDeclarativeInstruction::PopFetchedObject; |
|
1113 pop.line = prop->location.start.line; |
|
1114 output->bytecode << pop; |
|
1115 } |
|
1116 |
|
1117 foreach(Property *prop, obj->valueTypeProperties) { |
|
1118 QDeclarativeInstruction fetch; |
|
1119 fetch.type = QDeclarativeInstruction::FetchValueType; |
|
1120 fetch.fetchValue.property = prop->index; |
|
1121 fetch.fetchValue.type = prop->type; |
|
1122 fetch.line = prop->location.start.line; |
|
1123 |
|
1124 output->bytecode << fetch; |
|
1125 |
|
1126 foreach(Property *vprop, prop->value->valueProperties) { |
|
1127 genPropertyAssignment(vprop, prop->value, prop); |
|
1128 } |
|
1129 |
|
1130 QDeclarativeInstruction pop; |
|
1131 pop.type = QDeclarativeInstruction::PopValueType; |
|
1132 pop.fetchValue.property = prop->index; |
|
1133 pop.fetchValue.type = prop->type; |
|
1134 pop.line = prop->location.start.line; |
|
1135 output->bytecode << pop; |
|
1136 } |
|
1137 } |
|
1138 |
|
1139 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj) |
|
1140 { |
|
1141 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object; |
|
1142 Q_ASSERT(root); |
|
1143 |
|
1144 QDeclarativeInstruction create; |
|
1145 create.type = QDeclarativeInstruction::CreateComponent; |
|
1146 create.line = root->location.start.line; |
|
1147 create.createComponent.column = root->location.start.column; |
|
1148 create.createComponent.endLine = root->location.end.line; |
|
1149 output->bytecode << create; |
|
1150 int count = output->bytecode.count(); |
|
1151 |
|
1152 ComponentCompileState oldCompileState = compileState; |
|
1153 compileState = componentState(root); |
|
1154 |
|
1155 QDeclarativeInstruction init; |
|
1156 init.type = QDeclarativeInstruction::Init; |
|
1157 init.init.bindingsSize = compileState.bindings.count(); |
|
1158 init.init.parserStatusSize = compileState.parserStatusCount; |
|
1159 init.init.contextCache = genContextCache(); |
|
1160 if (compileState.compiledBindingData.isEmpty()) |
|
1161 init.init.compiledBinding = -1; |
|
1162 else |
|
1163 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); |
|
1164 init.line = obj->location.start.line; |
|
1165 output->bytecode << init; |
|
1166 |
|
1167 genObject(root); |
|
1168 |
|
1169 QDeclarativeInstruction def; |
|
1170 init.line = 0; |
|
1171 def.type = QDeclarativeInstruction::SetDefault; |
|
1172 output->bytecode << def; |
|
1173 |
|
1174 output->bytecode[count - 1].createComponent.count = |
|
1175 output->bytecode.count() - count; |
|
1176 |
|
1177 compileState = oldCompileState; |
|
1178 |
|
1179 if (!obj->id.isEmpty()) { |
|
1180 QDeclarativeInstruction id; |
|
1181 id.type = QDeclarativeInstruction::SetId; |
|
1182 id.line = 0; |
|
1183 id.setId.value = output->indexForString(obj->id); |
|
1184 id.setId.index = obj->idIndex; |
|
1185 output->bytecode << id; |
|
1186 } |
|
1187 } |
|
1188 |
|
1189 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj, |
|
1190 const BindingContext &ctxt) |
|
1191 { |
|
1192 // The special "Component" element can only have the id property and a |
|
1193 // default property, that actually defines the component's tree |
|
1194 |
|
1195 // Find, check and set the "id" property (if any) |
|
1196 Property *idProp = 0; |
|
1197 if (obj->properties.count() > 1 || |
|
1198 (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) |
|
1199 COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id")); |
|
1200 |
|
1201 if (obj->properties.count()) |
|
1202 idProp = *obj->properties.begin(); |
|
1203 |
|
1204 if (idProp) { |
|
1205 if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object) |
|
1206 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification")); |
|
1207 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive())) |
|
1208 |
|
1209 QString idVal = idProp->values.first()->primitive(); |
|
1210 |
|
1211 if (compileState.ids.contains(idVal)) |
|
1212 COMPILE_EXCEPTION(idProp, tr("id is not unique")); |
|
1213 |
|
1214 obj->id = idVal; |
|
1215 addId(idVal, obj); |
|
1216 } |
|
1217 |
|
1218 // Check the Component tree is well formed |
|
1219 if (obj->defaultProperty && |
|
1220 (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 || |
|
1221 (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object))) |
|
1222 COMPILE_EXCEPTION(obj, tr("Invalid component body specification")); |
|
1223 |
|
1224 if (!obj->dynamicProperties.isEmpty()) |
|
1225 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties.")); |
|
1226 if (!obj->dynamicSignals.isEmpty()) |
|
1227 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals.")); |
|
1228 if (!obj->dynamicSlots.isEmpty()) |
|
1229 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); |
|
1230 |
|
1231 Object *root = 0; |
|
1232 if (obj->defaultProperty && obj->defaultProperty->values.count()) |
|
1233 root = obj->defaultProperty->values.first()->object; |
|
1234 |
|
1235 if (!root) |
|
1236 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification")); |
|
1237 |
|
1238 // Build the component tree |
|
1239 COMPILE_CHECK(buildComponentFromRoot(root, ctxt)); |
|
1240 |
|
1241 return true; |
|
1242 } |
|
1243 |
|
1244 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj, |
|
1245 const BindingContext &ctxt) |
|
1246 { |
|
1247 ComponentCompileState oldComponentCompileState = compileState; |
|
1248 ComponentStat oldComponentStat = componentStat; |
|
1249 |
|
1250 compileState = ComponentCompileState(); |
|
1251 compileState.root = obj; |
|
1252 |
|
1253 componentStat = ComponentStat(); |
|
1254 componentStat.lineNumber = obj->location.start.line; |
|
1255 |
|
1256 if (obj) |
|
1257 COMPILE_CHECK(buildObject(obj, ctxt)); |
|
1258 |
|
1259 COMPILE_CHECK(completeComponentBuild()); |
|
1260 |
|
1261 compileState = oldComponentCompileState; |
|
1262 componentStat = oldComponentStat; |
|
1263 |
|
1264 return true; |
|
1265 } |
|
1266 |
|
1267 |
|
1268 // Build a sub-object. A sub-object is one that was not created directly by |
|
1269 // QML - such as a grouped property object, or an attached object. Sub-object's |
|
1270 // can't have an id, involve a custom parser, have attached properties etc. |
|
1271 bool QDeclarativeCompiler::buildSubObject(Object *obj, const BindingContext &ctxt) |
|
1272 { |
|
1273 Q_ASSERT(obj->metatype); |
|
1274 Q_ASSERT(!obj->defaultProperty); |
|
1275 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding |
|
1276 // sub-context |
|
1277 |
|
1278 foreach(Property *prop, obj->properties) { |
|
1279 if (isSignalPropertyName(prop->name)) { |
|
1280 COMPILE_CHECK(buildSignal(prop, obj, ctxt)); |
|
1281 } else { |
|
1282 COMPILE_CHECK(buildProperty(prop, obj, ctxt)); |
|
1283 } |
|
1284 } |
|
1285 |
|
1286 return true; |
|
1287 } |
|
1288 |
|
1289 int QDeclarativeCompiler::componentTypeRef() |
|
1290 { |
|
1291 QDeclarativeType *t = QDeclarativeMetaType::qmlType("Qt/Component",4,7); |
|
1292 for (int ii = output->types.count() - 1; ii >= 0; --ii) { |
|
1293 if (output->types.at(ii).type == t) |
|
1294 return ii; |
|
1295 } |
|
1296 QDeclarativeCompiledData::TypeReference ref; |
|
1297 ref.className = "Component"; |
|
1298 ref.type = t; |
|
1299 output->types << ref; |
|
1300 return output->types.count() - 1; |
|
1301 } |
|
1302 |
|
1303 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj, |
|
1304 const BindingContext &ctxt) |
|
1305 { |
|
1306 Q_ASSERT(obj->metaObject()); |
|
1307 |
|
1308 QByteArray name = prop->name; |
|
1309 Q_ASSERT(name.startsWith("on")); |
|
1310 name = name.mid(2); |
|
1311 if(name[0] >= 'A' && name[0] <= 'Z') |
|
1312 name[0] = name[0] - 'A' + 'a'; |
|
1313 |
|
1314 int sigIdx = QDeclarativePropertyPrivate::findSignalByName(obj->metaObject(), name).methodIndex(); |
|
1315 |
|
1316 if (sigIdx == -1) { |
|
1317 |
|
1318 // If the "on<Signal>" name doesn't resolve into a signal, try it as a |
|
1319 // property. |
|
1320 COMPILE_CHECK(buildProperty(prop, obj, ctxt)); |
|
1321 |
|
1322 } else { |
|
1323 |
|
1324 if (prop->value || prop->values.count() != 1) |
|
1325 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment")); |
|
1326 |
|
1327 prop->index = sigIdx; |
|
1328 obj->addSignalProperty(prop); |
|
1329 |
|
1330 if (prop->values.at(0)->object) { |
|
1331 COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt)); |
|
1332 prop->values.at(0)->type = Value::SignalObject; |
|
1333 } else { |
|
1334 prop->values.at(0)->type = Value::SignalExpression; |
|
1335 |
|
1336 if (!prop->values.at(0)->value.isScript()) |
|
1337 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)")); |
|
1338 |
|
1339 QString script = prop->values.at(0)->value.asScript().trimmed(); |
|
1340 if (script.isEmpty()) |
|
1341 COMPILE_EXCEPTION(prop, tr("Empty signal assignment")); |
|
1342 |
|
1343 compileState.signalExpressions.insert(prop->values.at(0), ctxt); |
|
1344 } |
|
1345 } |
|
1346 |
|
1347 return true; |
|
1348 } |
|
1349 |
|
1350 |
|
1351 /*! |
|
1352 Returns true if (value) property \a prop exists on obj, false otherwise. |
|
1353 */ |
|
1354 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop, |
|
1355 QDeclarativeParser::Object *obj) |
|
1356 { |
|
1357 if(isAttachedPropertyName(prop->name) || prop->name == "id") |
|
1358 return true; |
|
1359 |
|
1360 const QMetaObject *mo = obj->metaObject(); |
|
1361 if (mo) { |
|
1362 if (prop->isDefault) { |
|
1363 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo); |
|
1364 return p.name() != 0; |
|
1365 } else { |
|
1366 int idx = mo->indexOfProperty(prop->name.constData()); |
|
1367 return idx != -1; |
|
1368 } |
|
1369 } |
|
1370 |
|
1371 return false; |
|
1372 } |
|
1373 |
|
1374 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, |
|
1375 QDeclarativeParser::Object *obj, |
|
1376 const BindingContext &ctxt) |
|
1377 { |
|
1378 if (prop->isEmpty()) |
|
1379 COMPILE_EXCEPTION(prop, tr("Empty property assignment")); |
|
1380 |
|
1381 const QMetaObject *metaObject = obj->metaObject(); |
|
1382 Q_ASSERT(metaObject); |
|
1383 |
|
1384 if (isAttachedPropertyName(prop->name)) { |
|
1385 // Setup attached property data |
|
1386 |
|
1387 if (ctxt.isSubContext()) { |
|
1388 // Attached properties cannot be used on sub-objects. Sub-objects |
|
1389 // always exist in a binding sub-context, which is what we test |
|
1390 // for here. |
|
1391 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here")); |
|
1392 } |
|
1393 |
|
1394 QDeclarativeType *type = 0; |
|
1395 QDeclarativeImportedNamespace *typeNamespace = 0; |
|
1396 enginePrivate->importDatabase.resolveType(unit->imports, prop->name, |
|
1397 &type, 0, 0, 0, &typeNamespace); |
|
1398 |
|
1399 if (typeNamespace) { |
|
1400 // ### We might need to indicate that this property is a namespace |
|
1401 // for the DOM API |
|
1402 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, |
|
1403 ctxt)); |
|
1404 return true; |
|
1405 } else if (!type || !type->attachedPropertiesType()) { |
|
1406 COMPILE_EXCEPTION(prop, tr("Non-existent attached object")); |
|
1407 } |
|
1408 |
|
1409 if (!prop->value) |
|
1410 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment")); |
|
1411 |
|
1412 Q_ASSERT(type->attachedPropertiesFunction()); |
|
1413 prop->index = type->index(); |
|
1414 prop->value->metatype = type->attachedPropertiesType(); |
|
1415 } else { |
|
1416 // Setup regular property data |
|
1417 QMetaProperty p; |
|
1418 |
|
1419 if (prop->isDefault) { |
|
1420 p = QDeclarativeMetaType::defaultProperty(metaObject); |
|
1421 |
|
1422 if (p.name()) { |
|
1423 prop->index = p.propertyIndex(); |
|
1424 prop->name = p.name(); |
|
1425 } |
|
1426 |
|
1427 } else { |
|
1428 prop->index = metaObject->indexOfProperty(prop->name.constData()); |
|
1429 |
|
1430 if (prop->index != -1) { |
|
1431 p = metaObject->property(prop->index); |
|
1432 Q_ASSERT(p.name()); |
|
1433 } |
|
1434 } |
|
1435 |
|
1436 // We can't error here as the "id" property does not require a |
|
1437 // successful index resolution |
|
1438 if (p.name()) { |
|
1439 prop->type = p.userType(); |
|
1440 } |
|
1441 } |
|
1442 |
|
1443 if (prop->index != -1) |
|
1444 prop->parent->setBindingBit(prop->index); |
|
1445 |
|
1446 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) { |
|
1447 |
|
1448 // The magic "id" behavior doesn't apply when "id" is resolved as a |
|
1449 // default property or to sub-objects (which are always in binding |
|
1450 // sub-contexts) |
|
1451 COMPILE_CHECK(buildIdProperty(prop, obj)); |
|
1452 if (prop->type == QVariant::String && |
|
1453 prop->values.at(0)->value.isString()) |
|
1454 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); |
|
1455 |
|
1456 } else if (isAttachedPropertyName(prop->name)) { |
|
1457 |
|
1458 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); |
|
1459 |
|
1460 } else if (prop->index == -1) { |
|
1461 |
|
1462 if (prop->isDefault) { |
|
1463 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property")); |
|
1464 } else { |
|
1465 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name))); |
|
1466 } |
|
1467 |
|
1468 } else if (prop->value) { |
|
1469 |
|
1470 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt)); |
|
1471 |
|
1472 } else if (enginePrivate->isList(prop->type)) { |
|
1473 |
|
1474 COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); |
|
1475 |
|
1476 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) { |
|
1477 |
|
1478 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt)); |
|
1479 |
|
1480 } else { |
|
1481 |
|
1482 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); |
|
1483 |
|
1484 } |
|
1485 |
|
1486 return true; |
|
1487 } |
|
1488 |
|
1489 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns, |
|
1490 QDeclarativeParser::Property *nsProp, |
|
1491 QDeclarativeParser::Object *obj, |
|
1492 const BindingContext &ctxt) |
|
1493 { |
|
1494 if (!nsProp->value) |
|
1495 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace")); |
|
1496 |
|
1497 foreach (Property *prop, nsProp->value->properties) { |
|
1498 |
|
1499 if (!isAttachedPropertyName(prop->name)) |
|
1500 COMPILE_EXCEPTION(prop, tr("Not an attached property name")); |
|
1501 |
|
1502 // Setup attached property data |
|
1503 |
|
1504 QDeclarativeType *type = 0; |
|
1505 enginePrivate->importDatabase.resolveTypeInNamespace(ns, prop->name, &type, 0, 0, 0); |
|
1506 |
|
1507 if (!type || !type->attachedPropertiesType()) |
|
1508 COMPILE_EXCEPTION(prop, tr("Non-existent attached object")); |
|
1509 |
|
1510 if (!prop->value) |
|
1511 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment")); |
|
1512 |
|
1513 Q_ASSERT(type->attachedPropertiesFunction()); |
|
1514 prop->index = type->index(); |
|
1515 prop->value->metatype = type->attachedPropertiesType(); |
|
1516 |
|
1517 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); |
|
1518 } |
|
1519 |
|
1520 return true; |
|
1521 } |
|
1522 |
|
1523 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop, |
|
1524 QDeclarativeParser::Object *obj) |
|
1525 { |
|
1526 if (enginePrivate->isList(prop->type)) { |
|
1527 genListProperty(prop, obj); |
|
1528 } else { |
|
1529 genPropertyAssignment(prop, obj); |
|
1530 } |
|
1531 } |
|
1532 |
|
1533 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop, |
|
1534 QDeclarativeParser::Object *obj) |
|
1535 { |
|
1536 int listType = enginePrivate->listType(prop->type); |
|
1537 |
|
1538 QDeclarativeInstruction fetch; |
|
1539 fetch.type = QDeclarativeInstruction::FetchQList; |
|
1540 fetch.line = prop->location.start.line; |
|
1541 fetch.fetchQmlList.property = prop->index; |
|
1542 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType); |
|
1543 fetch.fetchQmlList.type = listType; |
|
1544 output->bytecode << fetch; |
|
1545 |
|
1546 for (int ii = 0; ii < prop->values.count(); ++ii) { |
|
1547 Value *v = prop->values.at(ii); |
|
1548 |
|
1549 if (v->type == Value::CreatedObject) { |
|
1550 |
|
1551 genObject(v->object); |
|
1552 if (listTypeIsInterface) { |
|
1553 QDeclarativeInstruction assign; |
|
1554 assign.type = QDeclarativeInstruction::AssignObjectList; |
|
1555 assign.line = prop->location.start.line; |
|
1556 output->bytecode << assign; |
|
1557 } else { |
|
1558 QDeclarativeInstruction store; |
|
1559 store.type = QDeclarativeInstruction::StoreObjectQList; |
|
1560 store.line = prop->location.start.line; |
|
1561 output->bytecode << store; |
|
1562 } |
|
1563 |
|
1564 } else if (v->type == Value::PropertyBinding) { |
|
1565 |
|
1566 genBindingAssignment(v, prop, obj); |
|
1567 |
|
1568 } |
|
1569 |
|
1570 } |
|
1571 |
|
1572 QDeclarativeInstruction pop; |
|
1573 pop.type = QDeclarativeInstruction::PopQList; |
|
1574 pop.line = prop->location.start.line; |
|
1575 output->bytecode << pop; |
|
1576 } |
|
1577 |
|
1578 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop, |
|
1579 QDeclarativeParser::Object *obj, |
|
1580 QDeclarativeParser::Property *valueTypeProperty) |
|
1581 { |
|
1582 for (int ii = 0; ii < prop->values.count(); ++ii) { |
|
1583 QDeclarativeParser::Value *v = prop->values.at(ii); |
|
1584 |
|
1585 Q_ASSERT(v->type == Value::CreatedObject || |
|
1586 v->type == Value::PropertyBinding || |
|
1587 v->type == Value::Literal); |
|
1588 |
|
1589 if (v->type == Value::CreatedObject) { |
|
1590 |
|
1591 genObject(v->object); |
|
1592 |
|
1593 if (QDeclarativeMetaType::isInterface(prop->type)) { |
|
1594 |
|
1595 QDeclarativeInstruction store; |
|
1596 store.type = QDeclarativeInstruction::StoreInterface; |
|
1597 store.line = v->object->location.start.line; |
|
1598 store.storeObject.propertyIndex = prop->index; |
|
1599 output->bytecode << store; |
|
1600 |
|
1601 } else if (prop->type == -1) { |
|
1602 |
|
1603 QDeclarativeInstruction store; |
|
1604 store.type = QDeclarativeInstruction::StoreVariantObject; |
|
1605 store.line = v->object->location.start.line; |
|
1606 store.storeObject.propertyIndex = prop->index; |
|
1607 output->bytecode << store; |
|
1608 |
|
1609 } else { |
|
1610 |
|
1611 QDeclarativeInstruction store; |
|
1612 store.type = QDeclarativeInstruction::StoreObject; |
|
1613 store.line = v->object->location.start.line; |
|
1614 store.storeObject.propertyIndex = prop->index; |
|
1615 output->bytecode << store; |
|
1616 |
|
1617 } |
|
1618 } else if (v->type == Value::PropertyBinding) { |
|
1619 |
|
1620 genBindingAssignment(v, prop, obj, valueTypeProperty); |
|
1621 |
|
1622 } else if (v->type == Value::Literal) { |
|
1623 |
|
1624 QMetaProperty mp = obj->metaObject()->property(prop->index); |
|
1625 genLiteralAssignment(mp, v); |
|
1626 |
|
1627 } |
|
1628 |
|
1629 } |
|
1630 |
|
1631 for (int ii = 0; ii < prop->onValues.count(); ++ii) { |
|
1632 |
|
1633 QDeclarativeParser::Value *v = prop->onValues.at(ii); |
|
1634 |
|
1635 Q_ASSERT(v->type == Value::ValueSource || |
|
1636 v->type == Value::ValueInterceptor); |
|
1637 |
|
1638 if (v->type == Value::ValueSource) { |
|
1639 genObject(v->object); |
|
1640 |
|
1641 QDeclarativeInstruction store; |
|
1642 store.type = QDeclarativeInstruction::StoreValueSource; |
|
1643 store.line = v->object->location.start.line; |
|
1644 if (valueTypeProperty) { |
|
1645 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty); |
|
1646 store.assignValueSource.owner = 1; |
|
1647 } else { |
|
1648 store.assignValueSource.property = genPropertyData(prop); |
|
1649 store.assignValueSource.owner = 0; |
|
1650 } |
|
1651 QDeclarativeType *valueType = toQmlType(v->object); |
|
1652 store.assignValueSource.castValue = valueType->propertyValueSourceCast(); |
|
1653 output->bytecode << store; |
|
1654 |
|
1655 } else if (v->type == Value::ValueInterceptor) { |
|
1656 genObject(v->object); |
|
1657 |
|
1658 QDeclarativeInstruction store; |
|
1659 store.type = QDeclarativeInstruction::StoreValueInterceptor; |
|
1660 store.line = v->object->location.start.line; |
|
1661 if (valueTypeProperty) { |
|
1662 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty); |
|
1663 store.assignValueInterceptor.owner = 1; |
|
1664 } else { |
|
1665 store.assignValueInterceptor.property = genPropertyData(prop); |
|
1666 store.assignValueInterceptor.owner = 0; |
|
1667 } |
|
1668 QDeclarativeType *valueType = toQmlType(v->object); |
|
1669 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast(); |
|
1670 output->bytecode << store; |
|
1671 } |
|
1672 |
|
1673 } |
|
1674 } |
|
1675 |
|
1676 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop, |
|
1677 QDeclarativeParser::Object *obj) |
|
1678 { |
|
1679 if (prop->value || |
|
1680 prop->values.count() > 1 || |
|
1681 prop->values.at(0)->object) |
|
1682 COMPILE_EXCEPTION(prop, tr("Invalid use of id property")); |
|
1683 |
|
1684 QDeclarativeParser::Value *idValue = prop->values.at(0); |
|
1685 QString val = idValue->primitive(); |
|
1686 |
|
1687 COMPILE_CHECK(checkValidId(idValue, val)); |
|
1688 |
|
1689 if (compileState.ids.contains(val)) |
|
1690 COMPILE_EXCEPTION(prop, tr("id is not unique")); |
|
1691 |
|
1692 prop->values.at(0)->type = Value::Id; |
|
1693 |
|
1694 obj->id = val; |
|
1695 addId(val, obj); |
|
1696 |
|
1697 return true; |
|
1698 } |
|
1699 |
|
1700 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj) |
|
1701 { |
|
1702 Q_ASSERT(!compileState.ids.contains(id)); |
|
1703 Q_ASSERT(obj->id == id); |
|
1704 obj->idIndex = compileState.ids.count(); |
|
1705 compileState.ids.insert(id, obj); |
|
1706 compileState.idIndexes.insert(obj->idIndex, obj); |
|
1707 } |
|
1708 |
|
1709 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref) |
|
1710 { |
|
1711 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value)); |
|
1712 compileState.bindings.insert(ref.value, ref); |
|
1713 } |
|
1714 |
|
1715 void QDeclarativeCompiler::saveComponentState() |
|
1716 { |
|
1717 Q_ASSERT(compileState.root); |
|
1718 Q_ASSERT(!savedCompileStates.contains(compileState.root)); |
|
1719 |
|
1720 savedCompileStates.insert(compileState.root, compileState); |
|
1721 savedComponentStats.append(componentStat); |
|
1722 } |
|
1723 |
|
1724 QDeclarativeCompiler::ComponentCompileState |
|
1725 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj) |
|
1726 { |
|
1727 Q_ASSERT(savedCompileStates.contains(obj)); |
|
1728 return savedCompileStates.value(obj); |
|
1729 } |
|
1730 |
|
1731 // Build attached property object. In this example, |
|
1732 // Text { |
|
1733 // GridView.row: 10 |
|
1734 // } |
|
1735 // GridView is an attached property object. |
|
1736 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop, |
|
1737 QDeclarativeParser::Object *obj, |
|
1738 const BindingContext &ctxt) |
|
1739 { |
|
1740 Q_ASSERT(prop->value); |
|
1741 Q_ASSERT(prop->index != -1); // This is set in buildProperty() |
|
1742 |
|
1743 obj->addAttachedProperty(prop); |
|
1744 |
|
1745 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); |
|
1746 |
|
1747 return true; |
|
1748 } |
|
1749 |
|
1750 |
|
1751 // Build "grouped" properties. In this example: |
|
1752 // Text { |
|
1753 // font.pointSize: 12 |
|
1754 // font.family: "Helvetica" |
|
1755 // } |
|
1756 // font is a nested property. pointSize and family are not. |
|
1757 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop, |
|
1758 QDeclarativeParser::Object *obj, |
|
1759 const BindingContext &ctxt) |
|
1760 { |
|
1761 Q_ASSERT(prop->type != 0); |
|
1762 Q_ASSERT(prop->index != -1); |
|
1763 |
|
1764 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) { |
|
1765 QDeclarativeEnginePrivate *ep = |
|
1766 static_cast<QDeclarativeEnginePrivate *>(QObjectPrivate::get(engine)); |
|
1767 if (prop->type >= 0 /* QVariant == -1 */ && ep->valueTypes[prop->type]) { |
|
1768 |
|
1769 if (prop->values.count()) { |
|
1770 if (prop->values.at(0)->location < prop->value->location) { |
|
1771 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value")); |
|
1772 } else { |
|
1773 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value")); |
|
1774 } |
|
1775 } |
|
1776 |
|
1777 if (!obj->metaObject()->property(prop->index).isWritable()) { |
|
1778 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); |
|
1779 } |
|
1780 |
|
1781 COMPILE_CHECK(buildValueTypeProperty(ep->valueTypes[prop->type], |
|
1782 prop->value, obj, ctxt.incr())); |
|
1783 obj->addValueTypeProperty(prop); |
|
1784 } else { |
|
1785 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); |
|
1786 } |
|
1787 |
|
1788 } else { |
|
1789 // Load the nested property's meta type |
|
1790 prop->value->metatype = enginePrivate->metaObjectForType(prop->type); |
|
1791 if (!prop->value->metatype) |
|
1792 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); |
|
1793 |
|
1794 if (prop->values.count()) |
|
1795 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property")); |
|
1796 |
|
1797 obj->addGroupedProperty(prop); |
|
1798 |
|
1799 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); |
|
1800 } |
|
1801 |
|
1802 return true; |
|
1803 } |
|
1804 |
|
1805 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, |
|
1806 QDeclarativeParser::Object *obj, |
|
1807 QDeclarativeParser::Object *baseObj, |
|
1808 const BindingContext &ctxt) |
|
1809 { |
|
1810 if (obj->defaultProperty) |
|
1811 COMPILE_EXCEPTION(obj, tr("Invalid property use")); |
|
1812 obj->metatype = type->metaObject(); |
|
1813 |
|
1814 foreach (Property *prop, obj->properties) { |
|
1815 int idx = type->metaObject()->indexOfProperty(prop->name.constData()); |
|
1816 if (idx == -1) |
|
1817 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name))); |
|
1818 QMetaProperty p = type->metaObject()->property(idx); |
|
1819 prop->index = idx; |
|
1820 prop->type = p.userType(); |
|
1821 prop->isValueTypeSubProperty = true; |
|
1822 |
|
1823 if (prop->value) |
|
1824 COMPILE_EXCEPTION(prop, tr("Property assignment expected")); |
|
1825 |
|
1826 if (prop->values.count() > 1) { |
|
1827 COMPILE_EXCEPTION(prop, tr("Single property assignment expected")); |
|
1828 } else if (prop->values.count()) { |
|
1829 Value *value = prop->values.at(0); |
|
1830 |
|
1831 if (value->object) { |
|
1832 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment")); |
|
1833 } else if (value->value.isScript()) { |
|
1834 // ### Check for writability |
|
1835 BindingReference reference; |
|
1836 reference.expression = value->value; |
|
1837 reference.property = prop; |
|
1838 reference.value = value; |
|
1839 reference.bindingContext = ctxt; |
|
1840 reference.bindingContext.owner++; |
|
1841 addBindingReference(reference); |
|
1842 value->type = Value::PropertyBinding; |
|
1843 } else { |
|
1844 COMPILE_CHECK(testLiteralAssignment(p, value)); |
|
1845 value->type = Value::Literal; |
|
1846 } |
|
1847 } |
|
1848 |
|
1849 for (int ii = 0; ii < prop->onValues.count(); ++ii) { |
|
1850 Value *v = prop->onValues.at(ii); |
|
1851 Q_ASSERT(v->object); |
|
1852 |
|
1853 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); |
|
1854 } |
|
1855 |
|
1856 obj->addValueProperty(prop); |
|
1857 } |
|
1858 |
|
1859 return true; |
|
1860 } |
|
1861 |
|
1862 // Build assignments to QML lists. QML lists are properties of type |
|
1863 // QDeclarativeListProperty<T>. List properties can accept a list of |
|
1864 // objects, or a single binding. |
|
1865 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop, |
|
1866 QDeclarativeParser::Object *obj, |
|
1867 const BindingContext &ctxt) |
|
1868 { |
|
1869 Q_ASSERT(enginePrivate->isList(prop->type)); |
|
1870 |
|
1871 int t = prop->type; |
|
1872 |
|
1873 obj->addValueProperty(prop); |
|
1874 |
|
1875 int listType = enginePrivate->listType(t); |
|
1876 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType); |
|
1877 |
|
1878 bool assignedBinding = false; |
|
1879 for (int ii = 0; ii < prop->values.count(); ++ii) { |
|
1880 Value *v = prop->values.at(ii); |
|
1881 if (v->object) { |
|
1882 v->type = Value::CreatedObject; |
|
1883 COMPILE_CHECK(buildObject(v->object, ctxt)); |
|
1884 |
|
1885 // We check object coercian here. We check interface assignment |
|
1886 // at runtime. |
|
1887 if (!listTypeIsInterface) { |
|
1888 if (!canCoerce(listType, v->object)) { |
|
1889 COMPILE_EXCEPTION(v, tr("Cannot assign object to list")); |
|
1890 } |
|
1891 } |
|
1892 |
|
1893 } else if (v->value.isScript()) { |
|
1894 if (assignedBinding) |
|
1895 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists")); |
|
1896 |
|
1897 assignedBinding = true; |
|
1898 COMPILE_CHECK(buildBinding(v, prop, ctxt)); |
|
1899 v->type = Value::PropertyBinding; |
|
1900 } else { |
|
1901 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists")); |
|
1902 } |
|
1903 } |
|
1904 |
|
1905 return true; |
|
1906 } |
|
1907 |
|
1908 // Compiles an assignment to a QDeclarativeScriptString property |
|
1909 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop, |
|
1910 QDeclarativeParser::Object *obj, |
|
1911 const BindingContext &ctxt) |
|
1912 { |
|
1913 if (prop->values.count() > 1) |
|
1914 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property")); |
|
1915 |
|
1916 if (prop->values.at(0)->object) |
|
1917 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected")); |
|
1918 |
|
1919 obj->addScriptStringProperty(prop, ctxt.stack); |
|
1920 |
|
1921 return true; |
|
1922 } |
|
1923 |
|
1924 // Compile regular property assignments of the form "property: <value>" |
|
1925 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop, |
|
1926 QDeclarativeParser::Object *obj, |
|
1927 const BindingContext &ctxt) |
|
1928 { |
|
1929 obj->addValueProperty(prop); |
|
1930 |
|
1931 for (int ii = 0; ii < prop->values.count(); ++ii) { |
|
1932 Value *v = prop->values.at(ii); |
|
1933 if (v->object) { |
|
1934 |
|
1935 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); |
|
1936 |
|
1937 } else { |
|
1938 |
|
1939 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt)); |
|
1940 |
|
1941 } |
|
1942 } |
|
1943 |
|
1944 for (int ii = 0; ii < prop->onValues.count(); ++ii) { |
|
1945 Value *v = prop->onValues.at(ii); |
|
1946 |
|
1947 Q_ASSERT(v->object); |
|
1948 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt)); |
|
1949 } |
|
1950 |
|
1951 return true; |
|
1952 } |
|
1953 |
|
1954 // Compile assigning a single object instance to a regular property |
|
1955 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop, |
|
1956 QDeclarativeParser::Object *obj, |
|
1957 QDeclarativeParser::Value *v, |
|
1958 const BindingContext &ctxt) |
|
1959 { |
|
1960 Q_ASSERT(prop->index != -1); |
|
1961 Q_ASSERT(v->object->type != -1); |
|
1962 |
|
1963 if (!obj->metaObject()->property(prop->index).isWritable()) |
|
1964 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); |
|
1965 |
|
1966 if (QDeclarativeMetaType::isInterface(prop->type)) { |
|
1967 |
|
1968 // Assigning an object to an interface ptr property |
|
1969 COMPILE_CHECK(buildObject(v->object, ctxt)); |
|
1970 |
|
1971 v->type = Value::CreatedObject; |
|
1972 |
|
1973 } else if (prop->type == -1) { |
|
1974 |
|
1975 // Assigning an object to a QVariant |
|
1976 COMPILE_CHECK(buildObject(v->object, ctxt)); |
|
1977 |
|
1978 v->type = Value::CreatedObject; |
|
1979 } else { |
|
1980 // Normally buildObject() will set this up, but we need the static |
|
1981 // meta object earlier to test for assignability. It doesn't matter |
|
1982 // that there may still be outstanding synthesized meta object changes |
|
1983 // on this type, as they are not relevant for assignability testing |
|
1984 v->object->metatype = output->types.at(v->object->type).metaObject(); |
|
1985 Q_ASSERT(v->object->metaObject()); |
|
1986 |
|
1987 // We want to raw metaObject here as the raw metaobject is the |
|
1988 // actual property type before we applied any extensions that might |
|
1989 // effect the properties on the type, but don't effect assignability |
|
1990 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type); |
|
1991 |
|
1992 // Will be true if the assgned type inherits propertyMetaObject |
|
1993 bool isAssignable = false; |
|
1994 // Determine isAssignable value |
|
1995 if (propertyMetaObject) { |
|
1996 const QMetaObject *c = v->object->metatype; |
|
1997 while(c) { |
|
1998 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject)); |
|
1999 c = c->superClass(); |
|
2000 } |
|
2001 } |
|
2002 |
|
2003 if (isAssignable) { |
|
2004 // Simple assignment |
|
2005 COMPILE_CHECK(buildObject(v->object, ctxt)); |
|
2006 |
|
2007 v->type = Value::CreatedObject; |
|
2008 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) { |
|
2009 // Automatic "Component" insertion |
|
2010 QDeclarativeParser::Object *root = v->object; |
|
2011 QDeclarativeParser::Object *component = new QDeclarativeParser::Object; |
|
2012 component->type = componentTypeRef(); |
|
2013 component->typeName = "Qt/Component"; |
|
2014 component->metatype = &QDeclarativeComponent::staticMetaObject; |
|
2015 component->location = root->location; |
|
2016 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value; |
|
2017 componentValue->object = root; |
|
2018 component->getDefaultProperty()->addValue(componentValue); |
|
2019 v->object = component; |
|
2020 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); |
|
2021 } else { |
|
2022 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property")); |
|
2023 } |
|
2024 } |
|
2025 |
|
2026 return true; |
|
2027 } |
|
2028 |
|
2029 // Compile assigning a single object instance to a regular property using the "on" syntax. |
|
2030 // |
|
2031 // For example: |
|
2032 // Item { |
|
2033 // NumberAnimation on x { } |
|
2034 // } |
|
2035 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop, |
|
2036 QDeclarativeParser::Object *obj, |
|
2037 QDeclarativeParser::Object *baseObj, |
|
2038 QDeclarativeParser::Value *v, |
|
2039 const BindingContext &ctxt) |
|
2040 { |
|
2041 Q_ASSERT(prop->index != -1); |
|
2042 Q_ASSERT(v->object->type != -1); |
|
2043 |
|
2044 if (!obj->metaObject()->property(prop->index).isWritable()) |
|
2045 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); |
|
2046 |
|
2047 |
|
2048 // Normally buildObject() will set this up, but we need the static |
|
2049 // meta object earlier to test for assignability. It doesn't matter |
|
2050 // that there may still be outstanding synthesized meta object changes |
|
2051 // on this type, as they are not relevant for assignability testing |
|
2052 v->object->metatype = output->types.at(v->object->type).metaObject(); |
|
2053 Q_ASSERT(v->object->metaObject()); |
|
2054 |
|
2055 // Will be true if the assigned type inherits QDeclarativePropertyValueSource |
|
2056 bool isPropertyValue = false; |
|
2057 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor |
|
2058 bool isPropertyInterceptor = false; |
|
2059 if (QDeclarativeType *valueType = toQmlType(v->object)) { |
|
2060 isPropertyValue = valueType->propertyValueSourceCast() != -1; |
|
2061 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1; |
|
2062 } |
|
2063 |
|
2064 if (isPropertyValue || isPropertyInterceptor) { |
|
2065 // Assign as a property value source |
|
2066 COMPILE_CHECK(buildObject(v->object, ctxt)); |
|
2067 |
|
2068 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty()) |
|
2069 buildDynamicMeta(baseObj, ForceCreation); |
|
2070 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor; |
|
2071 } else { |
|
2072 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData()))); |
|
2073 } |
|
2074 |
|
2075 return true; |
|
2076 } |
|
2077 |
|
2078 // Compile assigning a literal or binding to a regular property |
|
2079 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop, |
|
2080 QDeclarativeParser::Object *obj, |
|
2081 QDeclarativeParser::Value *v, |
|
2082 const BindingContext &ctxt) |
|
2083 { |
|
2084 Q_ASSERT(prop->index != -1); |
|
2085 |
|
2086 if (v->value.isScript()) { |
|
2087 |
|
2088 //optimization for <Type>.<EnumValue> enum assignments |
|
2089 bool isEnumAssignment = false; |
|
2090 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment)); |
|
2091 if (isEnumAssignment) { |
|
2092 v->type = Value::Literal; |
|
2093 return true; |
|
2094 } |
|
2095 |
|
2096 COMPILE_CHECK(buildBinding(v, prop, ctxt)); |
|
2097 |
|
2098 v->type = Value::PropertyBinding; |
|
2099 |
|
2100 } else { |
|
2101 |
|
2102 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v)); |
|
2103 |
|
2104 v->type = Value::Literal; |
|
2105 } |
|
2106 |
|
2107 return true; |
|
2108 } |
|
2109 |
|
2110 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop, |
|
2111 QDeclarativeParser::Object *obj, |
|
2112 QDeclarativeParser::Value *v, |
|
2113 bool *isAssignment) |
|
2114 { |
|
2115 *isAssignment = false; |
|
2116 if (!prop.isEnumType()) |
|
2117 return true; |
|
2118 |
|
2119 if (!prop.isWritable()) |
|
2120 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name()))); |
|
2121 |
|
2122 QString string = v->value.asString(); |
|
2123 if (!string.at(0).isUpper()) |
|
2124 return true; |
|
2125 |
|
2126 QStringList parts = string.split(QLatin1Char('.')); |
|
2127 if (parts.count() != 2) |
|
2128 return true; |
|
2129 |
|
2130 QString typeName = parts.at(0); |
|
2131 QDeclarativeType *type = 0; |
|
2132 enginePrivate->importDatabase.resolveType(unit->imports, typeName.toUtf8(), |
|
2133 &type, 0, 0, 0, 0); |
|
2134 |
|
2135 if (!type || obj->typeName != type->qmlTypeName()) |
|
2136 return true; |
|
2137 |
|
2138 QString enumValue = parts.at(1); |
|
2139 int value; |
|
2140 if (prop.isFlagType()) { |
|
2141 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData()); |
|
2142 } else |
|
2143 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData()); |
|
2144 if (value == -1) |
|
2145 return true; |
|
2146 |
|
2147 v->type = Value::Literal; |
|
2148 v->value = QDeclarativeParser::Variant(enumValue); |
|
2149 *isAssignment = true; |
|
2150 |
|
2151 return true; |
|
2152 } |
|
2153 |
|
2154 // Similar logic to above, but not knowing target property. |
|
2155 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const |
|
2156 { |
|
2157 int dot = script.indexOf('.'); |
|
2158 if (dot > 0) { |
|
2159 QDeclarativeType *type = 0; |
|
2160 enginePrivate->importDatabase.resolveType(unit->imports, script.left(dot), &type, 0, 0, 0, 0); |
|
2161 if (!type) |
|
2162 return -1; |
|
2163 const QMetaObject *mo = type->metaObject(); |
|
2164 const char *key = script.constData() + dot+1; |
|
2165 int i = mo->enumeratorCount(); |
|
2166 while (i--) { |
|
2167 int v = mo->enumerator(i).keyToValue(key); |
|
2168 if (v >= 0) |
|
2169 return v; |
|
2170 } |
|
2171 } |
|
2172 return -1; |
|
2173 } |
|
2174 |
|
2175 // Ensures that the dynamic meta specification on obj is valid |
|
2176 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj) |
|
2177 { |
|
2178 QSet<QByteArray> propNames; |
|
2179 QSet<QByteArray> methodNames; |
|
2180 bool seenDefaultProperty = false; |
|
2181 |
|
2182 // Check properties |
|
2183 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { |
|
2184 const QDeclarativeParser::Object::DynamicProperty &prop = |
|
2185 obj->dynamicProperties.at(ii); |
|
2186 |
|
2187 if (prop.isDefaultProperty) { |
|
2188 if (seenDefaultProperty) |
|
2189 COMPILE_EXCEPTION(&prop, tr("Duplicate default property")); |
|
2190 seenDefaultProperty = true; |
|
2191 } |
|
2192 |
|
2193 if (propNames.contains(prop.name)) |
|
2194 COMPILE_EXCEPTION(&prop, tr("Duplicate property name")); |
|
2195 |
|
2196 if (QString::fromUtf8(prop.name).at(0).isUpper()) |
|
2197 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter")); |
|
2198 propNames.insert(prop.name); |
|
2199 } |
|
2200 |
|
2201 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { |
|
2202 QByteArray name = obj->dynamicSignals.at(ii).name; |
|
2203 if (methodNames.contains(name)) |
|
2204 COMPILE_EXCEPTION(obj, tr("Duplicate signal name")); |
|
2205 if (QString::fromUtf8(name).at(0).isUpper()) |
|
2206 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter")); |
|
2207 methodNames.insert(name); |
|
2208 } |
|
2209 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { |
|
2210 QByteArray name = obj->dynamicSlots.at(ii).name; |
|
2211 if (methodNames.contains(name)) |
|
2212 COMPILE_EXCEPTION(obj, tr("Duplicate method name")); |
|
2213 if (QString::fromUtf8(name).at(0).isUpper()) |
|
2214 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter")); |
|
2215 methodNames.insert(name); |
|
2216 } |
|
2217 |
|
2218 return true; |
|
2219 } |
|
2220 |
|
2221 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj) |
|
2222 { |
|
2223 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { |
|
2224 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); |
|
2225 |
|
2226 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias) |
|
2227 continue; |
|
2228 |
|
2229 Property *property = 0; |
|
2230 if (p.isDefaultProperty) { |
|
2231 property = obj->getDefaultProperty(); |
|
2232 } else { |
|
2233 property = obj->getProperty(p.name); |
|
2234 if (!property->values.isEmpty()) |
|
2235 COMPILE_EXCEPTION(property, tr("Property value set multiple times")); |
|
2236 } |
|
2237 |
|
2238 if (property->value) |
|
2239 COMPILE_EXCEPTION(property, tr("Invalid property nesting")); |
|
2240 |
|
2241 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) { |
|
2242 Value *v = p.defaultValue->values.at(ii); |
|
2243 v->addref(); |
|
2244 property->values.append(v); |
|
2245 } |
|
2246 } |
|
2247 return true; |
|
2248 } |
|
2249 |
|
2250 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter) |
|
2251 |
|
2252 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode) |
|
2253 { |
|
2254 Q_ASSERT(obj); |
|
2255 Q_ASSERT(obj->metatype); |
|
2256 |
|
2257 if (mode != ForceCreation && |
|
2258 obj->dynamicProperties.isEmpty() && |
|
2259 obj->dynamicSignals.isEmpty() && |
|
2260 obj->dynamicSlots.isEmpty()) |
|
2261 return true; |
|
2262 |
|
2263 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0); |
|
2264 |
|
2265 QByteArray newClassName = obj->metatype->className(); |
|
2266 newClassName.append("_QML_"); |
|
2267 int idx = classIndexCounter()->fetchAndAddRelaxed(1); |
|
2268 newClassName.append(QByteArray::number(idx)); |
|
2269 if (compileState.root == obj) { |
|
2270 QString path = output->url.path(); |
|
2271 int lastSlash = path.lastIndexOf(QLatin1Char('/')); |
|
2272 if (lastSlash > -1) { |
|
2273 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); |
|
2274 if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) |
|
2275 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx); |
|
2276 } |
|
2277 } |
|
2278 |
|
2279 QMetaObjectBuilder builder; |
|
2280 builder.setClassName(newClassName); |
|
2281 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); |
|
2282 |
|
2283 bool hasAlias = false; |
|
2284 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { |
|
2285 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); |
|
2286 |
|
2287 int propIdx = |
|
2288 obj->metaObject()->indexOfProperty(p.name.constData()); |
|
2289 if (-1 != propIdx) { |
|
2290 QMetaProperty prop = obj->metaObject()->property(propIdx); |
|
2291 if (prop.isFinal()) |
|
2292 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property")); |
|
2293 } |
|
2294 |
|
2295 if (p.isDefaultProperty && |
|
2296 (p.type != Object::DynamicProperty::Alias || |
|
2297 mode == ResolveAliases)) |
|
2298 builder.addClassInfo("DefaultProperty", p.name); |
|
2299 |
|
2300 QByteArray type; |
|
2301 int propertyType = 0; |
|
2302 bool readonly = false; |
|
2303 switch(p.type) { |
|
2304 case Object::DynamicProperty::Alias: |
|
2305 hasAlias = true; |
|
2306 continue; |
|
2307 break; |
|
2308 case Object::DynamicProperty::CustomList: |
|
2309 case Object::DynamicProperty::Custom: |
|
2310 { |
|
2311 QByteArray customTypeName; |
|
2312 QDeclarativeType *qmltype = 0; |
|
2313 QUrl url; |
|
2314 if (!enginePrivate->importDatabase.resolveType(unit->imports, p.customType, &qmltype, |
|
2315 &url, 0, 0, 0)) |
|
2316 COMPILE_EXCEPTION(&p, tr("Invalid property type")); |
|
2317 |
|
2318 if (!qmltype) { |
|
2319 QDeclarativeCompositeTypeData *tdata = enginePrivate->typeManager.get(url); |
|
2320 Q_ASSERT(tdata); |
|
2321 Q_ASSERT(tdata->status == QDeclarativeCompositeTypeData::Complete); |
|
2322 |
|
2323 QDeclarativeCompiledData *data = tdata->toCompiledComponent(engine); |
|
2324 customTypeName = data->root->className(); |
|
2325 } else { |
|
2326 customTypeName = qmltype->typeName(); |
|
2327 } |
|
2328 |
|
2329 if (p.type == Object::DynamicProperty::Custom) { |
|
2330 type = customTypeName + '*'; |
|
2331 propertyType = QMetaType::QObjectStar; |
|
2332 } else { |
|
2333 readonly = true; |
|
2334 type = "QDeclarativeListProperty<"; |
|
2335 type.append(customTypeName); |
|
2336 type.append(">"); |
|
2337 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >(); |
|
2338 } |
|
2339 } |
|
2340 break; |
|
2341 case Object::DynamicProperty::Variant: |
|
2342 propertyType = -1; |
|
2343 type = "QVariant"; |
|
2344 break; |
|
2345 case Object::DynamicProperty::Int: |
|
2346 propertyType = QVariant::Int; |
|
2347 type = "int"; |
|
2348 break; |
|
2349 case Object::DynamicProperty::Bool: |
|
2350 propertyType = QVariant::Bool; |
|
2351 type = "bool"; |
|
2352 break; |
|
2353 case Object::DynamicProperty::Real: |
|
2354 propertyType = QVariant::Double; |
|
2355 type = "double"; |
|
2356 break; |
|
2357 case Object::DynamicProperty::String: |
|
2358 propertyType = QVariant::String; |
|
2359 type = "QString"; |
|
2360 break; |
|
2361 case Object::DynamicProperty::Url: |
|
2362 propertyType = QVariant::Url; |
|
2363 type = "QUrl"; |
|
2364 break; |
|
2365 case Object::DynamicProperty::Color: |
|
2366 propertyType = QVariant::Color; |
|
2367 type = "QColor"; |
|
2368 break; |
|
2369 case Object::DynamicProperty::Time: |
|
2370 propertyType = QVariant::Time; |
|
2371 type = "QTime"; |
|
2372 break; |
|
2373 case Object::DynamicProperty::Date: |
|
2374 propertyType = QVariant::Date; |
|
2375 type = "QDate"; |
|
2376 break; |
|
2377 case Object::DynamicProperty::DateTime: |
|
2378 propertyType = QVariant::DateTime; |
|
2379 type = "QDateTime"; |
|
2380 break; |
|
2381 } |
|
2382 |
|
2383 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++; |
|
2384 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType }; |
|
2385 dynamicData.append((char *)&propertyData, sizeof(propertyData)); |
|
2386 |
|
2387 builder.addSignal(p.name + "Changed()"); |
|
2388 QMetaPropertyBuilder propBuilder = |
|
2389 builder.addProperty(p.name, type, builder.methodCount() - 1); |
|
2390 propBuilder.setScriptable(true); |
|
2391 propBuilder.setWritable(!readonly); |
|
2392 } |
|
2393 |
|
2394 if (mode == ResolveAliases) { |
|
2395 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { |
|
2396 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); |
|
2397 |
|
2398 if (p.type == Object::DynamicProperty::Alias) { |
|
2399 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++; |
|
2400 compileAlias(builder, dynamicData, obj, p); |
|
2401 } |
|
2402 } |
|
2403 } |
|
2404 |
|
2405 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { |
|
2406 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii); |
|
2407 QByteArray sig(s.name + '('); |
|
2408 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) { |
|
2409 if (jj) sig.append(','); |
|
2410 sig.append(s.parameterTypes.at(jj)); |
|
2411 } |
|
2412 sig.append(')'); |
|
2413 QMetaMethodBuilder b = builder.addSignal(sig); |
|
2414 b.setParameterNames(s.parameterNames); |
|
2415 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++; |
|
2416 } |
|
2417 |
|
2418 QStringList funcScripts; |
|
2419 |
|
2420 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { |
|
2421 Object::DynamicSlot &s = obj->dynamicSlots[ii]; |
|
2422 QByteArray sig(s.name + '('); |
|
2423 QString funcScript(QLatin1String("(function(")); |
|
2424 |
|
2425 for (int jj = 0; jj < s.parameterNames.count(); ++jj) { |
|
2426 if (jj) { |
|
2427 sig.append(','); |
|
2428 funcScript.append(QLatin1Char(',')); |
|
2429 } |
|
2430 funcScript.append(QLatin1String(s.parameterNames.at(jj))); |
|
2431 sig.append("QVariant"); |
|
2432 } |
|
2433 sig.append(')'); |
|
2434 funcScript.append(QLatin1Char(')')); |
|
2435 funcScript.append(s.body); |
|
2436 funcScript.append(QLatin1Char(')')); |
|
2437 funcScripts << funcScript; |
|
2438 |
|
2439 QMetaMethodBuilder b = builder.addSlot(sig); |
|
2440 b.setReturnType("QVariant"); |
|
2441 b.setParameterNames(s.parameterNames); |
|
2442 |
|
2443 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++; |
|
2444 QDeclarativeVMEMetaData::MethodData methodData = |
|
2445 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line }; |
|
2446 |
|
2447 dynamicData.append((char *)&methodData, sizeof(methodData)); |
|
2448 } |
|
2449 |
|
2450 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { |
|
2451 const QString &funcScript = funcScripts.at(ii); |
|
2452 QDeclarativeVMEMetaData::MethodData *data = |
|
2453 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii; |
|
2454 |
|
2455 data->bodyOffset = dynamicData.size(); |
|
2456 |
|
2457 dynamicData.append((const char *)funcScript.constData(), |
|
2458 (funcScript.length() * sizeof(QChar))); |
|
2459 } |
|
2460 |
|
2461 obj->metadata = builder.toRelocatableData(); |
|
2462 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata); |
|
2463 |
|
2464 if (mode == IgnoreAliases && hasAlias) |
|
2465 compileState.aliasingObjects << obj; |
|
2466 |
|
2467 obj->synthdata = dynamicData; |
|
2468 |
|
2469 return true; |
|
2470 } |
|
2471 |
|
2472 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val) |
|
2473 { |
|
2474 if (val.isEmpty()) |
|
2475 COMPILE_EXCEPTION(v, tr( "Invalid empty ID")); |
|
2476 |
|
2477 if (val.at(0).isLetter() && !val.at(0).isLower()) |
|
2478 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter")); |
|
2479 |
|
2480 QChar u(QLatin1Char('_')); |
|
2481 for (int ii = 0; ii < val.count(); ++ii) { |
|
2482 |
|
2483 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) { |
|
2484 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore")); |
|
2485 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) { |
|
2486 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores")); |
|
2487 } |
|
2488 |
|
2489 } |
|
2490 |
|
2491 if (enginePrivate->globalClass->illegalNames().contains(val)) |
|
2492 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property")); |
|
2493 |
|
2494 return true; |
|
2495 } |
|
2496 |
|
2497 #include <qdeclarativejsparser_p.h> |
|
2498 |
|
2499 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node) |
|
2500 { |
|
2501 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) { |
|
2502 QString name = |
|
2503 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString(); |
|
2504 return QStringList() << name; |
|
2505 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) { |
|
2506 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node); |
|
2507 |
|
2508 QStringList rv = astNodeToStringList(expr->base); |
|
2509 if (rv.isEmpty()) |
|
2510 return rv; |
|
2511 rv.append(expr->name->asString()); |
|
2512 return rv; |
|
2513 } |
|
2514 return QStringList(); |
|
2515 } |
|
2516 |
|
2517 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, |
|
2518 QByteArray &data, |
|
2519 Object *obj, |
|
2520 const Object::DynamicProperty &prop) |
|
2521 { |
|
2522 if (!prop.defaultValue) |
|
2523 COMPILE_EXCEPTION(obj, tr("No property alias location")); |
|
2524 |
|
2525 if (prop.defaultValue->values.count() != 1 || |
|
2526 prop.defaultValue->values.at(0)->object || |
|
2527 !prop.defaultValue->values.at(0)->value.isScript()) |
|
2528 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); |
|
2529 |
|
2530 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST(); |
|
2531 if (!node) |
|
2532 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen? |
|
2533 |
|
2534 QStringList alias = astNodeToStringList(node); |
|
2535 |
|
2536 if (alias.count() != 1 && alias.count() != 2) |
|
2537 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id> or <id>.<property>")); |
|
2538 |
|
2539 if (!compileState.ids.contains(alias.at(0))) |
|
2540 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); |
|
2541 |
|
2542 Object *idObject = compileState.ids[alias.at(0)]; |
|
2543 |
|
2544 QByteArray typeName; |
|
2545 |
|
2546 int propIdx = -1; |
|
2547 int flags = 0; |
|
2548 bool writable = false; |
|
2549 if (alias.count() == 2) { |
|
2550 propIdx = idObject->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData()); |
|
2551 |
|
2552 if (-1 == propIdx) |
|
2553 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); |
|
2554 |
|
2555 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx); |
|
2556 writable = aliasProperty.isWritable(); |
|
2557 |
|
2558 if (aliasProperty.isEnumType()) |
|
2559 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject |
|
2560 else |
|
2561 typeName = aliasProperty.typeName(); |
|
2562 } else { |
|
2563 typeName = idObject->metaObject()->className(); |
|
2564 |
|
2565 //use the base type since it has been registered with metatype system |
|
2566 int index = typeName.indexOf("_QML_"); |
|
2567 if (index != -1) { |
|
2568 typeName = typeName.left(index); |
|
2569 } else { |
|
2570 index = typeName.indexOf("_QMLTYPE_"); |
|
2571 const QMetaObject *mo = idObject->metaObject(); |
|
2572 while (index != -1 && mo) { |
|
2573 typeName = mo->superClass()->className(); |
|
2574 index = typeName.indexOf("_QMLTYPE_"); |
|
2575 mo = mo->superClass(); |
|
2576 } |
|
2577 } |
|
2578 |
|
2579 typeName += '*'; |
|
2580 } |
|
2581 |
|
2582 if (typeName.endsWith('*')) |
|
2583 flags |= QML_ALIAS_FLAG_PTR; |
|
2584 |
|
2585 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex)); |
|
2586 data.append((const char *)&propIdx, sizeof(propIdx)); |
|
2587 data.append((const char *)&flags, sizeof(flags)); |
|
2588 |
|
2589 builder.addSignal(prop.name + "Changed()"); |
|
2590 QMetaPropertyBuilder propBuilder = |
|
2591 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1); |
|
2592 propBuilder.setScriptable(true); |
|
2593 propBuilder.setWritable(writable); |
|
2594 return true; |
|
2595 } |
|
2596 |
|
2597 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value, |
|
2598 QDeclarativeParser::Property *prop, |
|
2599 const BindingContext &ctxt) |
|
2600 { |
|
2601 Q_ASSERT(prop->index != -1); |
|
2602 Q_ASSERT(prop->parent); |
|
2603 Q_ASSERT(prop->parent->metaObject()); |
|
2604 |
|
2605 QMetaProperty mp = prop->parent->metaObject()->property(prop->index); |
|
2606 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type)) |
|
2607 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); |
|
2608 |
|
2609 BindingReference reference; |
|
2610 reference.expression = value->value; |
|
2611 reference.property = prop; |
|
2612 reference.value = value; |
|
2613 reference.bindingContext = ctxt; |
|
2614 addBindingReference(reference); |
|
2615 |
|
2616 return true; |
|
2617 } |
|
2618 |
|
2619 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding, |
|
2620 QDeclarativeParser::Property *prop, |
|
2621 QDeclarativeParser::Object *obj, |
|
2622 QDeclarativeParser::Property *valueTypeProperty) |
|
2623 { |
|
2624 Q_UNUSED(obj); |
|
2625 Q_ASSERT(compileState.bindings.contains(binding)); |
|
2626 |
|
2627 const BindingReference &ref = compileState.bindings.value(binding); |
|
2628 if (ref.dataType == BindingReference::Experimental) { |
|
2629 QDeclarativeInstruction store; |
|
2630 store.type = QDeclarativeInstruction::StoreCompiledBinding; |
|
2631 store.assignBinding.value = ref.compiledIndex; |
|
2632 store.assignBinding.context = ref.bindingContext.stack; |
|
2633 store.assignBinding.owner = ref.bindingContext.owner; |
|
2634 if (valueTypeProperty) |
|
2635 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) | |
|
2636 ((valueTypeProperty->type & 0xFF)) << 16 | |
|
2637 ((prop->index & 0xFF) << 24); |
|
2638 else |
|
2639 store.assignBinding.property = prop->index; |
|
2640 store.line = binding->location.start.line; |
|
2641 output->bytecode << store; |
|
2642 return; |
|
2643 } |
|
2644 |
|
2645 QDeclarativeInstruction store; |
|
2646 store.type = QDeclarativeInstruction::StoreBinding; |
|
2647 store.assignBinding.value = output->indexForByteArray(ref.compiledData); |
|
2648 store.assignBinding.context = ref.bindingContext.stack; |
|
2649 store.assignBinding.owner = ref.bindingContext.owner; |
|
2650 store.line = binding->location.start.line; |
|
2651 |
|
2652 Q_ASSERT(ref.bindingContext.owner == 0 || |
|
2653 (ref.bindingContext.owner != 0 && valueTypeProperty)); |
|
2654 if (ref.bindingContext.owner) { |
|
2655 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); |
|
2656 } else { |
|
2657 store.assignBinding.property = genPropertyData(prop); |
|
2658 } |
|
2659 |
|
2660 output->bytecode << store; |
|
2661 } |
|
2662 |
|
2663 int QDeclarativeCompiler::genContextCache() |
|
2664 { |
|
2665 if (compileState.ids.count() == 0) |
|
2666 return -1; |
|
2667 |
|
2668 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine); |
|
2669 |
|
2670 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin(); |
|
2671 iter != compileState.ids.end(); |
|
2672 ++iter) |
|
2673 cache->add(iter.key(), (*iter)->idIndex); |
|
2674 |
|
2675 output->contextCaches.append(cache); |
|
2676 return output->contextCaches.count() - 1; |
|
2677 } |
|
2678 |
|
2679 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp, |
|
2680 QDeclarativeParser::Property *prop) |
|
2681 { |
|
2682 QByteArray data = |
|
2683 QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index, |
|
2684 enginePrivate->valueTypes[prop->type]->metaObject(), |
|
2685 valueTypeProp->index); |
|
2686 // valueTypeProp->index, valueTypeProp->type); |
|
2687 |
|
2688 return output->indexForByteArray(data); |
|
2689 } |
|
2690 |
|
2691 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop) |
|
2692 { |
|
2693 return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index)); |
|
2694 } |
|
2695 |
|
2696 bool QDeclarativeCompiler::completeComponentBuild() |
|
2697 { |
|
2698 componentStat.ids = compileState.ids.count(); |
|
2699 |
|
2700 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) { |
|
2701 Object *aliasObject = compileState.aliasingObjects.at(ii); |
|
2702 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); |
|
2703 } |
|
2704 |
|
2705 QDeclarativeBindingCompiler::Expression expr; |
|
2706 expr.component = compileState.root; |
|
2707 expr.ids = compileState.ids; |
|
2708 |
|
2709 QDeclarativeBindingCompiler bindingCompiler; |
|
2710 |
|
2711 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); |
|
2712 iter != compileState.bindings.end(); ++iter) { |
|
2713 |
|
2714 BindingReference &binding = *iter; |
|
2715 |
|
2716 expr.context = binding.bindingContext.object; |
|
2717 expr.property = binding.property; |
|
2718 expr.expression = binding.expression; |
|
2719 expr.imports = unit->imports; |
|
2720 |
|
2721 int index = bindingCompiler.compile(expr, enginePrivate); |
|
2722 if (index != -1) { |
|
2723 binding.dataType = BindingReference::Experimental; |
|
2724 binding.compiledIndex = index; |
|
2725 componentStat.optimizedBindings.append(iter.key()->location); |
|
2726 continue; |
|
2727 } |
|
2728 |
|
2729 binding.dataType = BindingReference::QtScript; |
|
2730 |
|
2731 // Pre-rewrite the expression |
|
2732 QString expression = binding.expression.asScript(); |
|
2733 |
|
2734 // ### Optimize |
|
2735 QDeclarativeRewrite::SharedBindingTester sharableTest; |
|
2736 bool isSharable = sharableTest.isSharable(expression); |
|
2737 |
|
2738 QDeclarativeRewrite::RewriteBinding rewriteBinding; |
|
2739 expression = rewriteBinding(expression); |
|
2740 |
|
2741 quint32 length = expression.length(); |
|
2742 quint32 pc; |
|
2743 |
|
2744 if (isSharable) { |
|
2745 pc = output->cachedClosures.count(); |
|
2746 pc |= 0x80000000; |
|
2747 output->cachedClosures.append(0); |
|
2748 } else { |
|
2749 pc = output->cachedPrograms.length(); |
|
2750 output->cachedPrograms.append(0); |
|
2751 } |
|
2752 |
|
2753 binding.compiledData = |
|
2754 QByteArray((const char *)&pc, sizeof(quint32)) + |
|
2755 QByteArray((const char *)&length, sizeof(quint32)) + |
|
2756 QByteArray((const char *)expression.constData(), |
|
2757 expression.length() * sizeof(QChar)); |
|
2758 |
|
2759 componentStat.scriptBindings.append(iter.key()->location); |
|
2760 } |
|
2761 |
|
2762 if (bindingCompiler.isValid()) { |
|
2763 compileState.compiledBindingData = bindingCompiler.program(); |
|
2764 if (bindingsDump()) |
|
2765 QDeclarativeBindingCompiler::dump(compileState.compiledBindingData); |
|
2766 } |
|
2767 |
|
2768 saveComponentState(); |
|
2769 |
|
2770 return true; |
|
2771 } |
|
2772 |
|
2773 void QDeclarativeCompiler::dumpStats() |
|
2774 { |
|
2775 qWarning().nospace() << "QML Document: " << output->url.toString(); |
|
2776 for (int ii = 0; ii < savedComponentStats.count(); ++ii) { |
|
2777 const ComponentStat &stat = savedComponentStats.at(ii); |
|
2778 qWarning().nospace() << " Component Line " << stat.lineNumber; |
|
2779 qWarning().nospace() << " Total Objects: " << stat.objects; |
|
2780 qWarning().nospace() << " IDs Used: " << stat.ids; |
|
2781 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count(); |
|
2782 |
|
2783 { |
|
2784 QByteArray output; |
|
2785 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) { |
|
2786 if (0 == (ii % 10)) { |
|
2787 if (ii) output.append("\n"); |
|
2788 output.append(" "); |
|
2789 } |
|
2790 |
|
2791 output.append("("); |
|
2792 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line)); |
|
2793 output.append(":"); |
|
2794 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column)); |
|
2795 output.append(") "); |
|
2796 } |
|
2797 if (!output.isEmpty()) |
|
2798 qWarning().nospace() << output.constData(); |
|
2799 } |
|
2800 |
|
2801 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count(); |
|
2802 { |
|
2803 QByteArray output; |
|
2804 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) { |
|
2805 if (0 == (ii % 10)) { |
|
2806 if (ii) output.append("\n"); |
|
2807 output.append(" "); |
|
2808 } |
|
2809 |
|
2810 output.append("("); |
|
2811 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line)); |
|
2812 output.append(":"); |
|
2813 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column)); |
|
2814 output.append(") "); |
|
2815 } |
|
2816 if (!output.isEmpty()) |
|
2817 qWarning().nospace() << output.constData(); |
|
2818 } |
|
2819 } |
|
2820 } |
|
2821 |
|
2822 /*! |
|
2823 Returns true if from can be assigned to a (QObject) property of type |
|
2824 to. |
|
2825 */ |
|
2826 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from) |
|
2827 { |
|
2828 const QMetaObject *toMo = |
|
2829 enginePrivate->rawMetaObjectForType(to); |
|
2830 const QMetaObject *fromMo = from->metaObject(); |
|
2831 |
|
2832 while (fromMo) { |
|
2833 if (QDeclarativePropertyPrivate::equal(fromMo, toMo)) |
|
2834 return true; |
|
2835 fromMo = fromMo->superClass(); |
|
2836 } |
|
2837 return false; |
|
2838 } |
|
2839 |
|
2840 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from) |
|
2841 { |
|
2842 // ### Optimize |
|
2843 const QMetaObject *mo = from->metatype; |
|
2844 QDeclarativeType *type = 0; |
|
2845 while (!type && mo) { |
|
2846 type = QDeclarativeMetaType::qmlType(mo); |
|
2847 mo = mo->superClass(); |
|
2848 } |
|
2849 return type; |
|
2850 } |
|
2851 |
|
2852 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj) |
|
2853 { |
|
2854 const QMetaObject *mo = obj->metatype; |
|
2855 |
|
2856 int idx = mo->indexOfClassInfo("DeferredPropertyNames"); |
|
2857 if (idx == -1) |
|
2858 return QStringList(); |
|
2859 |
|
2860 QMetaClassInfo classInfo = mo->classInfo(idx); |
|
2861 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(',')); |
|
2862 return rv; |
|
2863 } |
|
2864 |
|
2865 QT_END_NAMESPACE |