Use the property cache when compiling the V4 instructions.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v4 / qv4irbuilder.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qv4irbuilder_p.h"
43 #include "qv4compiler_p_p.h"
44
45 #include <private/qquickanchors_p_p.h> // For AnchorLine
46 #include <private/qdeclarativetypenamecache_p.h>
47
48 DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
49
50 QT_BEGIN_NAMESPACE
51
52 using namespace QDeclarativeJS;
53
54 static IR::Type irTypeFromVariantType(int t, QDeclarativeEnginePrivate *engine, const QMetaObject * /* meta */)
55 {
56     switch (t) {
57     case QMetaType::Bool:
58         return IR::BoolType;
59
60     case QMetaType::Int:
61         return IR::IntType;
62
63     case QMetaType::QReal:
64         return IR::RealType;
65
66     case QMetaType::QString:
67         return IR::StringType;
68
69     case QMetaType::QUrl:
70         return IR::UrlType;
71
72     default:
73         if (t == qMetaTypeId<QDeclarative1AnchorLine>())
74             return IR::AnchorLineType;
75         else if (t == qMetaTypeId<QQuickAnchorLine>())
76             return IR::SGAnchorLineType;
77         else if (engine->metaObjectForType(t)) {
78             return IR::ObjectType;
79         }
80
81         return IR::InvalidType;
82     }
83 }
84
85 QV4IRBuilder::QV4IRBuilder(const QV4Compiler::Expression *expr, 
86                                                              QDeclarativeEnginePrivate *engine)
87 : m_expression(expr), m_engine(engine), _function(0), _block(0), _discard(false)
88 {
89 }
90
91 bool QV4IRBuilder::operator()(QDeclarativeJS::IR::Function *function,
92                                          QDeclarativeJS::AST::Node *ast)
93 {
94     bool discarded = false;
95
96     IR::BasicBlock *block = function->newBasicBlock();
97
98     qSwap(_discard, discarded);
99     qSwap(_function, function);
100     qSwap(_block, block);
101
102     ExprResult r;
103     AST::SourceLocation location;
104     if (AST::ExpressionNode *asExpr = ast->expressionCast()) {
105         r = expression(asExpr);
106         location = asExpr->firstSourceLocation();
107     } else if (AST::Statement *asStmt = ast->statementCast()) {
108         r = statement(asStmt);
109         location = asStmt->firstSourceLocation();
110     }
111
112     //_block->MOVE(_block->TEMP(IR::InvalidType), r.code);
113     if (r.code) {
114         const QMetaObject *m = 0;
115         const IR::Type targetType = irTypeFromVariantType(m_expression->property->type, m_engine, m);
116         if (targetType != r.type()) {
117             IR::Expr *x = _block->TEMP(targetType);
118             _block->MOVE(x, r, true);
119             r.code = x;
120         }
121         _block->RET(r.code, targetType, location.startLine, location.startColumn);
122     }
123
124     qSwap(_block, block);
125     qSwap(_function, function);
126     qSwap(_discard, discarded);
127
128     return !discarded;
129 }
130
131 bool QV4IRBuilder::buildName(QList<QStringRef> &name,
132                                               AST::Node *node,
133                                               QList<AST::ExpressionNode *> *nodes)
134 {
135     if (node->kind == AST::Node::Kind_IdentifierExpression) {
136         name << static_cast<AST::IdentifierExpression*>(node)->name;
137         if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
138     } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
139         AST::FieldMemberExpression *expr =
140             static_cast<AST::FieldMemberExpression *>(node);
141
142         if (!buildName(name, expr->base, nodes))
143             return false;
144
145         name << expr->name;
146         if (nodes) *nodes << expr;
147     } else {
148         return false;
149     }
150
151     return true;
152 }
153
154 void QV4IRBuilder::discard() 
155
156     _discard = true; 
157 }
158
159 QV4IRBuilder::ExprResult 
160 QV4IRBuilder::expression(AST::ExpressionNode *ast)
161 {
162     ExprResult r;
163     if (ast) {
164         qSwap(_expr, r);
165         accept(ast);
166         qSwap(_expr, r);
167
168         if (r.is(IR::InvalidType))
169             discard();
170         else {
171             Q_ASSERT(r.hint == r.format);
172         }
173     }
174
175     return r;
176 }
177
178 void QV4IRBuilder::condition(AST::ExpressionNode *ast, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
179 {
180     if (! ast)
181         return;
182     ExprResult r(iftrue, iffalse);
183     qSwap(_expr, r);
184     accept(ast);
185     qSwap(_expr, r);
186
187     if (r.format != ExprResult::cx) {
188         if (! r.code)
189             discard();
190
191         Q_ASSERT(r.hint == ExprResult::cx);
192         Q_ASSERT(r.format == ExprResult::ex);
193
194         if (r.type() != IR::BoolType) {
195             IR::Temp *t = _block->TEMP(IR::BoolType);
196             _block->MOVE(t, r);
197             r = t;
198         }
199
200         _block->CJUMP(_block->UNOP(IR::OpIfTrue, r), iftrue, iffalse);
201     }
202 }
203
204 QV4IRBuilder::ExprResult
205 QV4IRBuilder::statement(AST::Statement *ast)
206 {
207     ExprResult r;
208     if (ast) {
209         qSwap(_expr, r);
210         accept(ast);
211         qSwap(_expr, r);
212
213         if (r.is(IR::InvalidType))
214             discard();
215         else {
216             Q_ASSERT(r.hint == r.format);
217         }
218     }
219
220     return r;
221 }
222
223 void QV4IRBuilder::sourceElement(AST::SourceElement *ast)
224 {
225     accept(ast);
226 }
227
228 void QV4IRBuilder::implicitCvt(ExprResult &expr, IR::Type type)
229 {
230     if (expr.type() == type)
231         return; // nothing to do
232
233     IR::Expr *x = _block->TEMP(type);
234     _block->MOVE(x, expr.code);
235     expr.code = x;
236 }
237
238 // QML
239 bool QV4IRBuilder::visit(AST::UiProgram *)
240 {
241     Q_ASSERT(!"unreachable");
242     return false;
243 }
244
245 bool QV4IRBuilder::visit(AST::UiImportList *)
246 {
247     Q_ASSERT(!"unreachable");
248     return false;
249 }
250
251 bool QV4IRBuilder::visit(AST::UiImport *)
252 {
253     Q_ASSERT(!"unreachable");
254     return false;
255 }
256
257 bool QV4IRBuilder::visit(AST::UiPublicMember *)
258 {
259     Q_ASSERT(!"unreachable");
260     return false;
261 }
262
263 bool QV4IRBuilder::visit(AST::UiSourceElement *)
264 {
265     Q_ASSERT(!"unreachable");
266     return false;
267 }
268
269 bool QV4IRBuilder::visit(AST::UiObjectDefinition *)
270 {
271     Q_ASSERT(!"unreachable");
272     return false;
273 }
274
275 bool QV4IRBuilder::visit(AST::UiObjectInitializer *)
276 {
277     Q_ASSERT(!"unreachable");
278     return false;
279 }
280
281 bool QV4IRBuilder::visit(AST::UiObjectBinding *)
282 {
283     Q_ASSERT(!"unreachable");
284     return false;
285 }
286
287 bool QV4IRBuilder::visit(AST::UiScriptBinding *)
288 {
289     Q_ASSERT(!"unreachable");
290     return false;
291 }
292
293 bool QV4IRBuilder::visit(AST::UiArrayBinding *)
294 {
295     Q_ASSERT(!"unreachable");
296     return false;
297 }
298
299 bool QV4IRBuilder::visit(AST::UiObjectMemberList *)
300 {
301     Q_ASSERT(!"unreachable");
302     return false;
303 }
304
305 bool QV4IRBuilder::visit(AST::UiArrayMemberList *)
306 {
307     Q_ASSERT(!"unreachable");
308     return false;
309 }
310
311 bool QV4IRBuilder::visit(AST::UiQualifiedId *)
312 {
313     Q_ASSERT(!"unreachable");
314     return false;
315 }
316
317 bool QV4IRBuilder::visit(AST::UiSignature *)
318 {
319     Q_ASSERT(!"unreachable");
320     return false;
321 }
322
323 bool QV4IRBuilder::visit(AST::UiFormalList *)
324 {
325     Q_ASSERT(!"unreachable");
326     return false;
327 }
328
329 bool QV4IRBuilder::visit(AST::UiFormal *)
330 {
331     Q_ASSERT(!"unreachable");
332     return false;
333 }
334
335
336 // JS
337 bool QV4IRBuilder::visit(AST::Program *)
338 {
339     Q_ASSERT(!"unreachable");
340     return false;
341 }
342
343 bool QV4IRBuilder::visit(AST::SourceElements *)
344 {
345     Q_ASSERT(!"unreachable");
346     return false;
347 }
348
349 bool QV4IRBuilder::visit(AST::FunctionSourceElement *)
350 {
351     Q_ASSERT(!"unreachable");
352     return false;
353 }
354
355 bool QV4IRBuilder::visit(AST::StatementSourceElement *)
356 {
357     Q_ASSERT(!"unreachable");
358     return false;
359 }
360
361 // object literals
362 bool QV4IRBuilder::visit(AST::PropertyNameAndValueList *)
363 {
364     Q_ASSERT(!"unreachable");
365     return false;
366 }
367
368 bool QV4IRBuilder::visit(AST::IdentifierPropertyName *)
369 {
370     Q_ASSERT(!"unreachable");
371     return false;
372 }
373
374 bool QV4IRBuilder::visit(AST::StringLiteralPropertyName *)
375 {
376     Q_ASSERT(!"unreachable");
377     return false;
378 }
379
380 bool QV4IRBuilder::visit(AST::NumericLiteralPropertyName *)
381 {
382     Q_ASSERT(!"unreachable");
383     return false;
384 }
385
386
387 // array literals
388 bool QV4IRBuilder::visit(AST::ElementList *)
389 {
390     Q_ASSERT(!"unreachable");
391     return false;
392 }
393
394 bool QV4IRBuilder::visit(AST::Elision *)
395 {
396     Q_ASSERT(!"unreachable");
397     return false;
398 }
399
400
401 // function calls
402 bool QV4IRBuilder::visit(AST::ArgumentList *)
403 {
404     Q_ASSERT(!"unreachable");
405     return false;
406 }
407
408 // expressions
409 bool QV4IRBuilder::visit(AST::ObjectLiteral *)
410 {
411     return false;
412 }
413
414 bool QV4IRBuilder::visit(AST::ArrayLiteral *)
415 {
416     return false;
417 }
418
419 bool QV4IRBuilder::visit(AST::ThisExpression *)
420 {
421     return false;
422 }
423
424 bool QV4IRBuilder::visit(AST::IdentifierExpression *ast)
425 {
426     const quint32 line = ast->identifierToken.startLine;
427     const quint32 column = ast->identifierToken.startColumn;
428
429     const QString name = ast->name.toString();
430
431     if (name.at(0) == QLatin1Char('u') && name.length() == 9 && name == QLatin1String("undefined")) {
432         _expr.code = _block->CONST(IR::UndefinedType, 0); // ### undefined value
433     } else if (m_engine->v8engine()->illegalNames().contains(name) ) {
434         if (qmlVerboseCompiler()) qWarning() << "*** illegal symbol:" << name;
435         return false;
436     } else if (const QDeclarativeScript::Object *obj = m_expression->ids->value(name)) {
437         IR::Name *code = _block->ID_OBJECT(name, obj, line, column);
438         if (obj == m_expression->component)
439             code->storage = IR::Name::RootStorage;
440         _expr.code = code;
441     } else {
442
443         QDeclarativeTypeNameCache::Result r = m_expression->importCache->query(name);
444         if (r.isValid()) {
445             if (r.type) {
446                 _expr.code = _block->ATTACH_TYPE(name, r.type, IR::Name::ScopeStorage, line, column);
447             }
448             // We don't support anything else
449         } else {
450             bool found = false;
451
452             if (m_expression->context != m_expression->component) {
453                 // RootStorage is more efficient than ScopeStorage, so prefer that if they are the same
454                 QDeclarativePropertyCache *cache = m_expression->context->synthCache;
455                 const QMetaObject *metaObject = m_expression->context->metaObject();
456                 if (!cache) cache = m_engine->cache(metaObject);
457
458                 QDeclarativePropertyData *data = cache->property(name);
459
460                 if (data && data->revision != 0) {
461                     if (qmlVerboseCompiler()) 
462                         qWarning() << "*** versioned symbol:" << name;
463                     discard();
464                     return false;
465                 }
466
467                 if (data && !data->isFunction()) {
468                     IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject);
469                     _expr.code = _block->SYMBOL(irType, name, metaObject, data, IR::Name::ScopeStorage, line, column);
470                     found = true;
471                 } 
472             }
473
474             if (!found) {
475                 QDeclarativePropertyCache *cache = m_expression->component->synthCache;
476                 const QMetaObject *metaObject = m_expression->component->metaObject();
477                 if (!cache) cache = m_engine->cache(metaObject);
478
479                 QDeclarativePropertyData *data = cache->property(name);
480
481                 if (data && data->revision != 0) {
482                     if (qmlVerboseCompiler()) 
483                         qWarning() << "*** versioned symbol:" << name;
484                     discard();
485                     return false;
486                 }
487
488                 if (data && !data->isFunction()) {
489                     IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject);
490                     _expr.code = _block->SYMBOL(irType, name, metaObject, data, IR::Name::RootStorage, line, column);
491                     found = true;
492                 } 
493             }
494
495             if (!found && qmlVerboseCompiler())
496                 qWarning() << "*** unknown symbol:" << name;
497         }
498     }
499
500     if (_expr.code && _expr.hint == ExprResult::cx) {
501         _expr.format = ExprResult::cx;
502
503         if (_expr.type() != IR::BoolType) {
504             IR::Temp *t = _block->TEMP(IR::BoolType);
505             _block->MOVE(t, _expr);
506             _expr.code = t;
507         }
508
509         _block->CJUMP(_expr.code, _expr.iftrue, _expr.iffalse);
510         _expr.code = 0;
511     }
512
513     return false;
514 }
515
516 bool QV4IRBuilder::visit(AST::NullExpression *)
517 {
518     // ### TODO: cx format
519     _expr.code = _block->CONST(IR::NullType, 0);
520     return false;
521 }
522
523 bool QV4IRBuilder::visit(AST::TrueLiteral *)
524 {
525     // ### TODO: cx format
526     _expr.code = _block->CONST(IR::BoolType, 1);
527     return false;
528 }
529
530 bool QV4IRBuilder::visit(AST::FalseLiteral *)
531 {
532     // ### TODO: cx format
533     _expr.code = _block->CONST(IR::BoolType, 0);
534     return false;
535 }
536
537 bool QV4IRBuilder::visit(AST::StringLiteral *ast)
538 {
539     // ### TODO: cx format
540     _expr.code = _block->STRING(ast->value);
541     return false;
542 }
543
544 bool QV4IRBuilder::visit(AST::NumericLiteral *ast)
545 {
546     if (_expr.hint == ExprResult::cx) {
547         _expr.format = ExprResult::cx;
548         _block->JUMP(ast->value ? _expr.iftrue : _expr.iffalse);
549     } else {
550         _expr.code = _block->CONST(ast->value);
551     }
552     return false;
553 }
554
555 bool QV4IRBuilder::visit(AST::RegExpLiteral *)
556 {
557     return false;
558 }
559
560 bool QV4IRBuilder::visit(AST::NestedExpression *)
561 {
562     return true; // the value of the nested expression
563 }
564
565 bool QV4IRBuilder::visit(AST::ArrayMemberExpression *)
566 {
567     return false;
568 }
569
570 bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
571 {
572     if (IR::Expr *left = expression(ast->base)) {
573         if (IR::Name *baseName = left->asName()) {
574             const quint32 line = ast->identifierToken.startLine;
575             const quint32 column = ast->identifierToken.startColumn;
576
577             QString name = ast->name.toString();
578
579             switch(baseName->symbol) {
580             case IR::Name::Unbound:
581                 break;
582
583             case IR::Name::AttachType:
584                 if (name.at(0).isUpper()) {
585                     QByteArray utf8Name = name.toUtf8();
586                     const char *enumName = utf8Name.constData();
587
588                     const QMetaObject *meta = baseName->declarativeType->metaObject();
589                     bool found = false;
590                     for (int ii = 0; !found && ii < meta->enumeratorCount(); ++ii) {
591                         QMetaEnum e = meta->enumerator(ii);
592                         for (int jj = 0; !found && jj < e.keyCount(); ++jj) {
593                             if (0 == strcmp(e.key(jj), enumName)) {
594                                 found = true;
595                                 _expr.code = _block->CONST(IR::IntType, e.value(jj));
596                             }
597                         }
598                     }
599
600                     if (!found && qmlVerboseCompiler())
601                         qWarning() << "*** unresolved enum:" 
602                                    << (*baseName->id + QLatin1String(".") + ast->name.toString());
603                 } else if(const QMetaObject *attachedMeta = baseName->declarativeType->attachedPropertiesType()) {
604                     QDeclarativePropertyCache *cache = m_engine->cache(attachedMeta);
605                     QDeclarativePropertyData *data = cache->property(name);
606
607                     if (!data || data->isFunction())
608                         return false; // Don't support methods (or non-existing properties ;)
609
610                     if(!data->isFinal()) {
611                         if (qmlVerboseCompiler())
612                             qWarning() << "*** non-final attached property:"
613                                        << (*baseName->id + QLatin1String(".") + ast->name.toString());
614                         return false; // We don't know enough about this property
615                     }
616
617                     IR::Type irType = irTypeFromVariantType(data->propType, m_engine, attachedMeta);
618                     _expr.code = _block->SYMBOL(baseName, irType, name, attachedMeta, data, line, column);
619                 }
620                 break;
621
622             case IR::Name::IdObject: {
623                 const QDeclarativeScript::Object *idObject = baseName->idObject;
624                 QDeclarativePropertyCache *cache = 
625                     idObject->synthCache?idObject->synthCache:m_engine->cache(idObject->metaObject());
626
627                 QDeclarativePropertyData *data = cache->property(name);
628
629                 if (!data || data->isFunction())
630                     return false; // Don't support methods (or non-existing properties ;)
631
632                 if (data->revision != 0) {
633                     if (qmlVerboseCompiler()) 
634                         qWarning() << "*** versioned symbol:" << name;
635                     discard();
636                     return false;
637                 }
638
639                 IR::Type irType = irTypeFromVariantType(data->propType, m_engine, idObject->metaObject());
640                 _expr.code = _block->SYMBOL(baseName, irType, name,
641                                             idObject->metaObject(), data, line, column);
642                 }
643                 break;
644
645             case IR::Name::Property: 
646                 if (baseName->type == IR::ObjectType) {
647                     QDeclarativePropertyData *data = baseName->property;
648                     if (!data || data->isFunction())
649                         return false; // Don't support methods (or non-existing properties ;)
650
651                     if(!data->isFinal()) {
652                         if (qmlVerboseCompiler())
653                             qWarning() << "*** non-final property access:"
654                                 << (*baseName->id + QLatin1String(".") + ast->name.toString());
655                         return false; // We don't know enough about this property
656                     }
657
658                     IR::Type irType = irTypeFromVariantType(data->propType, m_engine, baseName->meta);
659                     _expr.code = _block->SYMBOL(baseName, irType, name,
660                                                 baseName->meta, data, line, column);
661                 }
662                 break;
663
664             case IR::Name::Object: 
665             case IR::Name::Slot:
666                 break;
667             }
668         }
669     }
670
671     return false;
672 }
673
674 bool QV4IRBuilder::preVisit(AST::Node *)
675 {
676     return ! _discard;
677 }
678
679 bool QV4IRBuilder::visit(AST::NewMemberExpression *)
680 {
681     return false;
682 }
683
684 bool QV4IRBuilder::visit(AST::NewExpression *)
685 {
686     return false;
687 }
688
689 bool QV4IRBuilder::visit(AST::CallExpression *ast)
690 {
691     QList<QStringRef> names;
692     QList<AST::ExpressionNode *> nameNodes;
693
694     names.reserve(4);
695     nameNodes.reserve(4);
696
697     if (buildName(names, ast->base, &nameNodes)) {
698         //ExprResult base = expression(ast->base);
699         QString id;
700         for (int i = 0; i < names.size(); ++i) {
701             if (! i)
702                 id += QLatin1Char('.');
703             id += names.at(i);
704         }
705         const AST::SourceLocation loc = nameNodes.last()->firstSourceLocation();
706         IR::Expr *base = _block->NAME(id, loc.startLine, loc.startColumn);
707
708         IR::ExprList *args = 0, **argsInserter = &args;
709         for (AST::ArgumentList *it = ast->arguments; it; it = it->next) {
710             IR::Expr *arg = expression(it->expression);
711             *argsInserter = _function->pool->New<IR::ExprList>();
712             (*argsInserter)->init(arg);
713             argsInserter = &(*argsInserter)->next;
714         }
715
716         IR::Temp *r = _block->TEMP(IR::InvalidType);
717         IR::Expr *call = _block->CALL(base, args);
718         _block->MOVE(r, call);
719         r->type = call->type;
720         _expr.code = r;
721     }
722
723     return false;
724 }
725
726 bool QV4IRBuilder::visit(AST::PostIncrementExpression *)
727 {
728     return false;
729 }
730
731 bool QV4IRBuilder::visit(AST::PostDecrementExpression *)
732 {
733     return false;
734 }
735
736 bool QV4IRBuilder::visit(AST::DeleteExpression *)
737 {
738     return false;
739 }
740
741 bool QV4IRBuilder::visit(AST::VoidExpression *)
742 {
743     return false;
744 }
745
746 bool QV4IRBuilder::visit(AST::TypeOfExpression *)
747 {
748     return false;
749 }
750
751 bool QV4IRBuilder::visit(AST::PreIncrementExpression *)
752 {
753     return false;
754 }
755
756 bool QV4IRBuilder::visit(AST::PreDecrementExpression *)
757 {
758     return false;
759 }
760
761 bool QV4IRBuilder::visit(AST::UnaryPlusExpression *ast)
762 {
763     ExprResult expr = expression(ast->expression);
764     if (expr.isNot(IR::InvalidType)) {
765         if (expr.code->asConst() != 0) {
766             _expr = expr;
767             return false;
768         }
769
770         IR::Expr *code = _block->UNOP(IR::OpUPlus, expr);
771         _expr.code = _block->TEMP(code->type);
772         _block->MOVE(_expr, code);
773     }
774
775     return false;
776 }
777
778 bool QV4IRBuilder::visit(AST::UnaryMinusExpression *ast)
779 {
780     ExprResult expr = expression(ast->expression);
781     if (expr.isNot(IR::InvalidType)) {
782         if (IR::Const *c = expr.code->asConst()) {
783             _expr = expr;
784             _expr.code = _block->CONST(-c->value);
785             return false;
786         }
787
788         IR::Expr *code = _block->UNOP(IR::OpUMinus, expr);
789         _expr.code = _block->TEMP(code->type);
790         _block->MOVE(_expr, code);
791     }
792
793     return false;
794 }
795
796 bool QV4IRBuilder::visit(AST::TildeExpression *ast)
797 {
798     ExprResult expr = expression(ast->expression);
799     if (expr.isNot(IR::InvalidType)) {
800         if (IR::Const *c = expr.code->asConst()) {
801             _expr = expr;
802             _expr.code = _block->CONST(~int(c->value));
803             return false;
804         }
805         IR::Expr *code = _block->UNOP(IR::OpCompl, expr);
806         _expr.code = _block->TEMP(code->type);
807         _block->MOVE(_expr, code);
808     }
809
810     return false;
811 }
812
813 bool QV4IRBuilder::visit(AST::NotExpression *ast)
814 {
815     ExprResult expr = expression(ast->expression);
816
817     if (expr.isNot(IR::InvalidType)) {
818         if (IR::Const *c = expr.code->asConst()) {
819             _expr = expr;
820             _expr.code = _block->CONST(!c->value);
821             return false;
822         }
823
824         IR::Expr *code = _block->UNOP(IR::OpNot, expr);
825         _expr.code = _block->TEMP(code->type);
826         _block->MOVE(_expr, code);
827
828     } else if (expr.hint == ExprResult::cx) {
829         expr.format = ExprResult::cx;
830         _block->CJUMP(_block->UNOP(IR::OpNot, expr), _expr.iftrue, _expr.iffalse);
831         return false;
832     }
833
834     return false;
835 }
836
837 void QV4IRBuilder::binop(AST::BinaryExpression *ast, ExprResult left, ExprResult right)
838 {
839     if (IR::Type t = maxType(left.type(), right.type())) {
840         implicitCvt(left, t);
841         implicitCvt(right, t);
842
843         if (_expr.hint == ExprResult::cx) {
844             _expr.format = ExprResult::cx;
845             _block->CJUMP(_block->BINOP(IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse);
846         } else {
847             IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
848             _expr.code = _block->TEMP(code->type);
849             _block->MOVE(_expr.code, code);
850         }
851     }
852 }
853
854 bool QV4IRBuilder::visit(AST::BinaryExpression *ast)
855 {
856     switch (ast->op) {
857     case QSOperator::And: {
858         if (_expr.hint == ExprResult::cx) {
859             _expr.format = ExprResult::cx;
860
861             Q_ASSERT(_expr.iffalse != 0);
862             Q_ASSERT(_expr.iftrue != 0);
863
864             IR::BasicBlock *iftrue = _function->newBasicBlock();
865             condition(ast->left, iftrue, _expr.iffalse);
866
867             _block = iftrue;
868             condition(ast->right, _expr.iftrue, _expr.iffalse);
869         } else {
870             IR::BasicBlock *iftrue = _function->newBasicBlock();
871             IR::BasicBlock *iffalse = _function->newBasicBlock();
872             IR::BasicBlock *endif = _function->newBasicBlock();
873
874             condition(ast->left, iftrue, iffalse);
875
876             IR::Temp *r = _block->TEMP(IR::InvalidType);
877
878             _block = iffalse;
879             _block->MOVE(r, _block->CONST(0)); // ### use the right null value
880             _block->JUMP(endif);
881
882             _block = iftrue;
883             ExprResult right = expression(ast->right);
884             _block->MOVE(r, right);
885             _block->JUMP(endif);
886
887             _block = endif;
888
889             r->type = right.type(); // ### not exactly, it can be IR::BoolType.
890             _expr.code = r;
891         }
892     } break;
893
894     case QSOperator::Or: {
895         IR::BasicBlock *iftrue = _function->newBasicBlock();
896         IR::BasicBlock *endif = _function->newBasicBlock();
897
898         ExprResult left = expression(ast->left);
899         IR::Temp *r = _block->TEMP(left.type());
900         _block->MOVE(r, left);
901
902         IR::Expr *cond = r;
903         if (r->type != IR::BoolType) {
904             cond = _block->TEMP(IR::BoolType);
905             _block->MOVE(cond, r);
906         }
907
908         _block->CJUMP(_block->UNOP(IR::OpNot, cond), iftrue, endif);
909
910         _block = iftrue;
911         ExprResult right = expression(ast->right);
912         _block->MOVE(r, right);
913
914         if (left.type() != right.type())
915             discard();
916
917         _expr.code = r;
918
919         _block = endif;
920     } break;
921
922     case QSOperator::Lt:
923     case QSOperator::Gt:
924     case QSOperator::Le:
925     case QSOperator::Ge: {
926         ExprResult left = expression(ast->left);
927         ExprResult right = expression(ast->right);
928         if (left.type() == IR::StringType && right.type() == IR::StringType) {
929             binop(ast, left, right);
930         } else if (left.isValid() && right.isValid()) {
931             implicitCvt(left, IR::RealType);
932             implicitCvt(right, IR::RealType);
933             binop(ast, left, right);
934         }
935     } break;
936
937     case QSOperator::NotEqual:
938     case QSOperator::Equal: {
939         ExprResult left = expression(ast->left);
940         ExprResult right = expression(ast->right);
941         if ((left.type() == IR::NullType || left.type() == IR::UndefinedType) &&
942                 (right.type() == IR::NullType || right.type() == IR::UndefinedType)) {
943             const bool isEq = ast->op == QSOperator::Equal;
944             if (_expr.hint == ExprResult::cx) {
945                 _expr.format = ExprResult::cx;
946                 _block->JUMP(isEq ? _expr.iftrue : _expr.iffalse);
947             } else {
948                 _expr.code = _block->CONST(IR::BoolType, isEq ? 1 : 0);
949             }
950         } else if ((left.type() == IR::StringType && right.type() >= IR::FirstNumberType) ||
951                    (left.type() >= IR::FirstNumberType && right.type() == IR::StringType)) {
952             implicitCvt(left, IR::RealType);
953             implicitCvt(right, IR::RealType);
954             binop(ast, left, right);
955         } else if (left.type() == IR::BoolType || right.type() == IR::BoolType) {
956             implicitCvt(left, IR::BoolType);
957             implicitCvt(right, IR::BoolType);
958         } else if (left.isValid() && right.isValid()) {
959             binop(ast, left, right);
960         }
961     } break;
962
963     case QSOperator::StrictEqual:
964     case QSOperator::StrictNotEqual: {
965         ExprResult left = expression(ast->left);
966         ExprResult right = expression(ast->right);
967         if (left.type() == right.type()) {
968             binop(ast, left, right);
969         } else if (left.type() >= IR::BoolType && right.type() >= IR::BoolType) {
970             // left and right have numeric type (int or real)
971             binop(ast, left, right);
972         } else if (left.isValid() && right.isValid()) {
973             const bool isEq = ast->op == QSOperator::StrictEqual;
974             if (_expr.hint == ExprResult::cx) {
975                 _expr.format = ExprResult::cx;
976                 _block->JUMP(isEq ? _expr.iftrue : _expr.iffalse);
977             } else {
978                 _expr.code = _block->CONST(IR::BoolType, isEq ? 1 : 0);
979             }
980         }
981     } break;
982
983     case QSOperator::BitAnd:
984     case QSOperator::BitOr:
985     case QSOperator::BitXor:
986     case QSOperator::LShift:
987     case QSOperator::RShift:
988     case QSOperator::URShift: {
989         ExprResult left = expression(ast->left);
990         if (left.is(IR::InvalidType))
991             return false;
992
993         ExprResult right = expression(ast->right);
994         if (right.is(IR::InvalidType))
995             return false;
996
997         implicitCvt(left, IR::IntType);
998         implicitCvt(right, IR::IntType);
999
1000         IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
1001         _expr.code = _block->TEMP(code->type);
1002         _block->MOVE(_expr.code, code);
1003
1004     } break;
1005
1006     case QSOperator::Add: {
1007         ExprResult left = expression(ast->left);
1008         if (left.is(IR::InvalidType))
1009             return false;
1010
1011         ExprResult right = expression(ast->right);
1012         if (right.is(IR::InvalidType))
1013             return false;
1014
1015         if (left.isPrimitive() && right.isPrimitive()) {
1016             if (left.type() == IR::StringType || right.type() == IR::StringType) {
1017                 implicitCvt(left, IR::StringType);
1018                 implicitCvt(right, IR::StringType);
1019             }
1020             binop(ast, left, right);
1021         }
1022     } break;
1023
1024     case QSOperator::Div:
1025     case QSOperator::Mod:
1026     case QSOperator::Mul:
1027     case QSOperator::Sub: {
1028         ExprResult left = expression(ast->left);
1029         if (left.is(IR::InvalidType))
1030             return false;
1031
1032         ExprResult right = expression(ast->right);
1033         if (right.is(IR::InvalidType))
1034             return false;
1035
1036         IR::Type t = maxType(left.type(), right.type());
1037         if (t >= IR::FirstNumberType) {
1038             implicitCvt(left, IR::RealType);
1039             implicitCvt(right, IR::RealType);
1040
1041             IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
1042             _expr.code = _block->TEMP(code->type);
1043             _block->MOVE(_expr.code, code);
1044         }
1045     } break;
1046
1047     case QSOperator::In:
1048     case QSOperator::InstanceOf:
1049     case QSOperator::Assign:
1050     case QSOperator::InplaceAnd:
1051     case QSOperator::InplaceSub:
1052     case QSOperator::InplaceDiv:
1053     case QSOperator::InplaceAdd:
1054     case QSOperator::InplaceLeftShift:
1055     case QSOperator::InplaceMod:
1056     case QSOperator::InplaceMul:
1057     case QSOperator::InplaceOr:
1058     case QSOperator::InplaceRightShift:
1059     case QSOperator::InplaceURightShift:
1060     case QSOperator::InplaceXor:
1061         // yup, we don't do those.
1062         break;
1063     } // switch
1064
1065     return false;
1066 }
1067
1068 bool QV4IRBuilder::visit(AST::ConditionalExpression *ast)
1069 {
1070     IR::BasicBlock *iftrue = _function->newBasicBlock();
1071     IR::BasicBlock *iffalse = _function->newBasicBlock();
1072     IR::BasicBlock *endif = _function->newBasicBlock();
1073
1074     condition(ast->expression, iftrue, iffalse);
1075
1076     IR::Temp *r = _block->TEMP(IR::InvalidType);
1077
1078     qSwap(_block, iftrue);
1079     ExprResult ok = expression(ast->ok);
1080     _block->MOVE(r, ok);
1081     _block->JUMP(endif);
1082     qSwap(_block, iftrue);
1083
1084     qSwap(_block, iffalse);
1085     ExprResult ko = expression(ast->ko);
1086     _block->MOVE(r, ko);
1087     _block->JUMP(endif);
1088     qSwap(_block, iffalse);
1089
1090     r->type = maxType(ok.type(), ko.type());
1091     _expr.code = r;
1092
1093     _block = endif;
1094
1095     return false;
1096 }
1097
1098 bool QV4IRBuilder::visit(AST::Expression *ast)
1099 {
1100     _block->EXP(expression(ast->left));
1101     _expr = expression(ast->right);
1102
1103     return false;
1104 }
1105
1106
1107 // statements
1108 bool QV4IRBuilder::visit(AST::Block *ast)
1109 {
1110     if (ast->statements && ! ast->statements->next) {
1111         // we have one and only one statement
1112         accept(ast->statements->statement);
1113     }
1114
1115     return false;
1116 }
1117
1118 bool QV4IRBuilder::visit(AST::StatementList *)
1119 {
1120     return false;
1121 }
1122
1123 bool QV4IRBuilder::visit(AST::VariableStatement *)
1124 {
1125     return false;
1126 }
1127
1128 bool QV4IRBuilder::visit(AST::VariableDeclarationList *)
1129 {
1130     return false;
1131 }
1132
1133 bool QV4IRBuilder::visit(AST::VariableDeclaration *)
1134 {
1135     return false;
1136 }
1137
1138 bool QV4IRBuilder::visit(AST::EmptyStatement *)
1139 {
1140     return false;
1141 }
1142
1143 bool QV4IRBuilder::visit(AST::ExpressionStatement *ast)
1144 {
1145     if (ast->expression) {
1146          // return the value of this expression
1147         return true;
1148     }
1149
1150     return false;
1151 }
1152
1153 bool QV4IRBuilder::visit(AST::IfStatement *ast)
1154 {
1155     if (! ast->ko) {
1156         // This is an if statement without an else branch.
1157         discard();
1158     } else {
1159         IR::BasicBlock *iftrue = _function->newBasicBlock();
1160         IR::BasicBlock *iffalse = _function->newBasicBlock();
1161         IR::BasicBlock *endif = _function->newBasicBlock();
1162
1163         condition(ast->expression, iftrue, iffalse);
1164
1165         IR::Temp *r = _block->TEMP(IR::InvalidType);
1166
1167         qSwap(_block, iftrue);
1168         ExprResult ok = statement(ast->ok);
1169         _block->MOVE(r, ok);
1170         _block->JUMP(endif);
1171         qSwap(_block, iftrue);
1172
1173         qSwap(_block, iffalse);
1174         ExprResult ko = statement(ast->ko);
1175         _block->MOVE(r, ko);
1176         _block->JUMP(endif);
1177         qSwap(_block, iffalse);
1178
1179         r->type = maxType(ok.type(), ko.type());
1180         _expr.code = r;
1181
1182         _block = endif;
1183     }
1184
1185     return false;
1186 }
1187
1188 bool QV4IRBuilder::visit(AST::DoWhileStatement *)
1189 {
1190     return false;
1191 }
1192
1193 bool QV4IRBuilder::visit(AST::WhileStatement *)
1194 {
1195     return false;
1196 }
1197
1198 bool QV4IRBuilder::visit(AST::ForStatement *)
1199 {
1200     return false;
1201 }
1202
1203 bool QV4IRBuilder::visit(AST::LocalForStatement *)
1204 {
1205     return false;
1206 }
1207
1208 bool QV4IRBuilder::visit(AST::ForEachStatement *)
1209 {
1210     return false;
1211 }
1212
1213 bool QV4IRBuilder::visit(AST::LocalForEachStatement *)
1214 {
1215     discard();
1216     return false;
1217 }
1218
1219 bool QV4IRBuilder::visit(AST::ContinueStatement *)
1220 {
1221     return false;
1222 }
1223
1224 bool QV4IRBuilder::visit(AST::BreakStatement *)
1225 {
1226     return false;
1227 }
1228
1229 bool QV4IRBuilder::visit(AST::ReturnStatement *ast)
1230 {
1231     if (ast->expression) {
1232         // return the value of the expression
1233         return true;
1234     }
1235
1236     return false;
1237 }
1238
1239 bool QV4IRBuilder::visit(AST::WithStatement *)
1240 {
1241     return false;
1242 }
1243
1244 bool QV4IRBuilder::visit(AST::SwitchStatement *)
1245 {
1246     return false;
1247 }
1248
1249 bool QV4IRBuilder::visit(AST::CaseBlock *)
1250 {
1251     return false;
1252 }
1253
1254 bool QV4IRBuilder::visit(AST::CaseClauses *)
1255 {
1256     return false;
1257 }
1258
1259 bool QV4IRBuilder::visit(AST::CaseClause *)
1260 {
1261     return false;
1262 }
1263
1264 bool QV4IRBuilder::visit(AST::DefaultClause *)
1265 {
1266     return false;
1267 }
1268
1269 bool QV4IRBuilder::visit(AST::LabelledStatement *)
1270 {
1271     return false;
1272 }
1273
1274 bool QV4IRBuilder::visit(AST::ThrowStatement *)
1275 {
1276     return false;
1277 }
1278
1279 bool QV4IRBuilder::visit(AST::TryStatement *)
1280 {
1281     return false;
1282 }
1283
1284 bool QV4IRBuilder::visit(AST::Catch *)
1285 {
1286     return false;
1287 }
1288
1289 bool QV4IRBuilder::visit(AST::Finally *)
1290 {
1291     return false;
1292 }
1293
1294 bool QV4IRBuilder::visit(AST::FunctionDeclaration *)
1295 {
1296     return false;
1297 }
1298
1299 bool QV4IRBuilder::visit(AST::FunctionExpression *)
1300 {
1301     return false;
1302 }
1303
1304 bool QV4IRBuilder::visit(AST::FormalParameterList *)
1305 {
1306     return false;
1307 }
1308
1309 bool QV4IRBuilder::visit(AST::FunctionBody *)
1310 {
1311     return false;
1312 }
1313
1314 bool QV4IRBuilder::visit(AST::DebuggerStatement *)
1315 {
1316     return false;
1317 }
1318
1319 QT_END_NAMESPACE