Add QColor support to v4.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v4 / qv4ir.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qv4ir_p.h"
43
44 #include <QtCore/qtextstream.h>
45 #include <QtCore/qdebug.h>
46 #include <math.h>
47
48 QT_BEGIN_NAMESPACE
49
50 namespace QDeclarativeJS {
51 namespace IR {
52
53 inline const char *typeName(Type t)
54 {
55     switch (t) {
56     case InvalidType: return "invalid";
57     case UndefinedType: return "undefined";
58     case NullType: return "null";
59     case VoidType: return "void";
60     case StringType: return "string";
61     case UrlType: return "url";
62     case ColorType: return "color";
63     case SGAnchorLineType: return "SGAnchorLine";
64     case AttachType: return "AttachType";
65     case ObjectType: return "object";
66     case BoolType: return "bool";
67     case IntType: return "int";
68     case RealType: return "qreal";
69     case RealNaNType: return "NaN";
70     default: return "invalid";
71     }
72 }
73
74 inline bool isNumberType(IR::Type ty)
75 {
76     return ty >= IR::FirstNumberType;
77 }
78
79 inline bool isStringType(IR::Type ty)
80 {
81     return ty == IR::StringType || ty == IR::UrlType || ty == IR::ColorType;
82 }
83
84 IR::Type maxType(IR::Type left, IR::Type right)
85 {
86     if (isStringType(left) && isStringType(right)) {
87         // String promotions (url to string) are more specific than
88         // identity conversions (AKA left == right). That's because
89         // we want to ensure we convert urls to strings in binary
90         // expressions.
91         return IR::StringType;
92     } else if (left == right)
93         return left;
94     else if (isNumberType(left) && isNumberType(right))
95         return qMax(left, right);
96     else if ((isNumberType(left) && isStringType(right)) ||
97              (isNumberType(right) && isStringType(left)))
98         return IR::StringType;
99     else
100         return IR::InvalidType;
101 }
102
103
104 const char *opname(AluOp op)
105 {
106     switch (op) {
107     case OpInvalid: return "?";
108
109     case OpIfTrue: return "(bool)";
110     case OpNot: return "!";
111     case OpUMinus: return "-";
112     case OpUPlus: return "+";
113     case OpCompl: return "~";
114
115     case OpBitAnd: return "&";
116     case OpBitOr: return "|";
117     case OpBitXor: return "^";
118
119     case OpAdd: return "+";
120     case OpSub: return "-";
121     case OpMul: return "*";
122     case OpDiv: return "/";
123     case OpMod: return "%";
124
125     case OpLShift: return "<<";
126     case OpRShift: return ">>";
127     case OpURShift: return ">>>";
128
129     case OpGt: return ">";
130     case OpLt: return "<";
131     case OpGe: return ">=";
132     case OpLe: return "<=";
133     case OpEqual: return "==";
134     case OpNotEqual: return "!=";
135     case OpStrictEqual: return "===";
136     case OpStrictNotEqual: return "!==";
137
138     case OpAnd: return "&&";
139     case OpOr: return "||";
140
141     default: return "?";
142
143     } // switch
144 }
145
146 AluOp binaryOperator(int op)
147 {
148     switch (static_cast<QSOperator::Op>(op)) {
149     case QSOperator::Add: return OpAdd;
150     case QSOperator::And: return OpAnd;
151     case QSOperator::BitAnd: return OpBitAnd;
152     case QSOperator::BitOr: return OpBitOr;
153     case QSOperator::BitXor: return OpBitXor;
154     case QSOperator::Div: return OpDiv;
155     case QSOperator::Equal: return OpEqual;
156     case QSOperator::Ge: return OpGe;
157     case QSOperator::Gt: return OpGt;
158     case QSOperator::Le: return OpLe;
159     case QSOperator::LShift: return OpLShift;
160     case QSOperator::Lt: return OpLt;
161     case QSOperator::Mod: return OpMod;
162     case QSOperator::Mul: return OpMul;
163     case QSOperator::NotEqual: return OpNotEqual;
164     case QSOperator::Or: return OpOr;
165     case QSOperator::RShift: return OpRShift;
166     case QSOperator::StrictEqual: return OpStrictEqual;
167     case QSOperator::StrictNotEqual: return OpStrictNotEqual;
168     case QSOperator::Sub: return OpSub;
169     case QSOperator::URShift: return OpURShift;
170     default: return OpInvalid;
171     }
172 }
173
174 void Const::dump(QTextStream &out)
175 {
176     out << value;
177 }
178
179 void String::dump(QTextStream &out)
180 {
181     out << '"' << escape(value) << '"';
182 }
183
184 QString String::escape(const QStringRef &s)
185 {
186     QString r;
187     for (int i = 0; i < s.length(); ++i) {
188         const QChar ch = s.at(i);
189         if (ch == QLatin1Char('\n'))
190             r += QLatin1String("\\n");
191         else if (ch == QLatin1Char('\r'))
192             r += QLatin1String("\\r");
193         else if (ch == QLatin1Char('\\'))
194             r += QLatin1String("\\\\");
195         else if (ch == QLatin1Char('"'))
196             r += QLatin1String("\\\"");
197         else if (ch == QLatin1Char('\''))
198             r += QLatin1String("\\'");
199         else
200             r += ch;
201     }
202     return r;
203 }
204
205 void Name::init(Name *base, Type type, const QString *id, Symbol symbol, quint32 line, quint32 column)
206 {
207     this->type = type;
208     this->base = base;
209     this->id = id;
210     this->symbol = symbol;
211     this->ptr = 0;
212     this->property = 0;
213     this->storage = MemberStorage;
214     this->builtin = NoBuiltinSymbol;
215     this->line = line;
216     this->column = column;
217
218     if (id->length() == 8 && *id == QLatin1String("Math.sin")) {
219         builtin = MathSinBultinFunction;
220     } else if (id->length() == 8 && *id == QLatin1String("Math.cos")) {
221         builtin = MathCosBultinFunction;
222     } else if (id->length() == 10 && *id == QLatin1String("Math.round")) {
223         builtin = MathRoundBultinFunction;
224     } else if (id->length() == 10 && *id == QLatin1String("Math.floor)")) {
225         builtin = MathFloorBultinFunction;
226     } else if (id->length() == 7 && *id == QLatin1String("Math.PI")) {
227         builtin = MathPIBuiltinConstant;
228         this->type = RealType;
229     }
230 }
231
232 void Name::dump(QTextStream &out)
233 {
234     if (base) {
235         base->dump(out);
236         out << '.';
237     }
238
239     out << *id;
240 }
241
242 void Temp::dump(QTextStream &out)
243 {
244     out << 't' << index;
245 }
246
247 void Unop::dump(QTextStream &out)
248 {
249     out << opname(op);
250     expr->dump(out);
251 }
252
253 Type Unop::typeForOp(AluOp op, Expr *expr)
254 {
255     switch (op) {
256     case OpIfTrue: return BoolType;
257     case OpNot: return BoolType;
258
259     case OpUMinus:
260     case OpUPlus:
261     case OpCompl:
262         return maxType(expr->type, RealType);
263
264     default:
265         break;
266     }
267
268     return InvalidType;
269 }
270
271 void Binop::dump(QTextStream &out)
272 {
273     left->dump(out);
274     out << ' ' << opname(op) << ' ';
275     right->dump(out);
276 }
277
278 Type Binop::typeForOp(AluOp op, Expr *left, Expr *right)
279 {
280     if (! (left && right))
281         return InvalidType;
282
283     switch (op) {
284     case OpInvalid:
285         return InvalidType;
286
287     // unary operators
288     case OpIfTrue:
289     case OpNot:
290     case OpUMinus:
291     case OpUPlus:
292     case OpCompl:
293         return InvalidType;
294
295     // bit fields
296     case OpBitAnd:
297     case OpBitOr:
298     case OpBitXor:
299         return IntType;
300
301     case OpAdd:
302         if (left->type == StringType)
303             return StringType;
304         return RealType;
305
306     case OpSub:
307     case OpMul:
308     case OpDiv:
309     case OpMod:
310         return RealType;
311
312     case OpLShift:
313     case OpRShift:
314     case OpURShift:
315         return IntType;
316
317     case OpAnd:
318     case OpOr:
319         return BoolType;
320
321     case OpGt:
322     case OpLt:
323     case OpGe:
324     case OpLe:
325     case OpEqual:
326     case OpNotEqual:
327     case OpStrictEqual:
328     case OpStrictNotEqual:
329         return BoolType;
330     } // switch
331
332     return InvalidType;
333 }
334
335 void Call::dump(QTextStream &out)
336 {
337     base->dump(out);
338     out << '(';
339     for (ExprList *it = args; it; it = it->next) {
340         if (it != args)
341             out << ", ";
342         it->expr->dump(out);
343     }
344     out << ')';
345 }
346
347 Type Call::typeForFunction(Expr *base)
348 {
349     if (! base)
350         return InvalidType;
351
352     if (Name *name = base->asName()) {
353         switch (name->builtin) {
354         case MathSinBultinFunction:
355         case MathCosBultinFunction:
356             return RealType;
357
358         case MathRoundBultinFunction:
359         case MathFloorBultinFunction:
360             return IntType;
361
362         case NoBuiltinSymbol:
363         case MathPIBuiltinConstant:
364             break;
365         }
366     } // switch
367
368     return InvalidType;
369 }
370
371 void Exp::dump(QTextStream &out, Mode)
372 {
373     out << "(void) ";
374     expr->dump(out);
375     out << ';';
376 }
377
378 void Move::dump(QTextStream &out, Mode)
379 {
380     target->dump(out);
381     out << " = ";
382     if (source->type != target->type)
383         out << typeName(source->type) << "_to_" << typeName(target->type) << '(';
384     source->dump(out);
385     if (source->type != target->type)
386         out << ')';
387     out << ';';
388 }
389
390 void Jump::dump(QTextStream &out, Mode mode)
391 {
392     Q_UNUSED(mode);
393     out << "goto " << 'L' << target << ';';
394 }
395
396 void CJump::dump(QTextStream &out, Mode mode)
397 {
398     Q_UNUSED(mode);
399     out << "if (";
400     cond->dump(out);
401     out << ") goto " << 'L' << iftrue << "; else goto " << 'L' << iffalse << ';';
402 }
403
404 void Ret::dump(QTextStream &out, Mode)
405 {
406     out << "return";
407     if (expr) {
408         out << ' ';
409         expr->dump(out);
410     }
411     out << ';';
412 }
413
414 Function::~Function()
415 {
416     qDeleteAll(basicBlocks);
417 }
418
419 QString *Function::newString(const QString &text)
420 {
421     return pool->NewString(text);
422 }
423
424 BasicBlock *Function::newBasicBlock()
425 {
426     const int index = basicBlocks.size();
427     return i(new BasicBlock(this, index));
428 }
429
430 void Function::dump(QTextStream &out)
431 {
432     out << "function () {" << endl;
433     foreach (BasicBlock *bb, basicBlocks) {
434         bb->dump(out);
435     }
436     out << '}' << endl;
437 }
438
439 Temp *BasicBlock::TEMP(Type type, int index) 
440
441     Temp *e = function->pool->New<Temp>();
442     e->init(type, index);
443     return e;
444 }
445
446 Temp *BasicBlock::TEMP(Type type) 
447
448     return TEMP(type, function->tempCount++); 
449 }
450
451 Expr *BasicBlock::CONST(double value) 
452
453     return CONST(IR::RealType, value); 
454 }
455
456 Expr *BasicBlock::CONST(Type type, double value) 
457
458     Const *e = function->pool->New<Const>();
459     e->init(type, value);
460     return e;
461 }
462
463 Expr *BasicBlock::STRING(const QStringRef &value)
464 {
465     String *e = function->pool->New<String>();
466     e->init(value);
467     return e;
468 }
469
470 Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
471
472     return NAME(0, id, line, column);
473 }
474
475 Name *BasicBlock::NAME(Name *base, const QString &id, quint32 line, quint32 column)
476
477     Name *e = function->pool->New<Name>();
478     e->init(base, InvalidType,
479             function->newString(id),
480             Name::Unbound, line, column);
481     return e;
482 }
483
484 Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, QDeclarativePropertyData *property, Name::Storage storage,
485                          quint32 line, quint32 column)
486 {
487     Name *name = SYMBOL(/*base = */ 0, type, id, meta, property, line, column);
488     name->storage = storage;
489     return name;
490 }
491
492 Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QDeclarativePropertyData *property, Name::Storage storage,
493                          quint32 line, quint32 column)
494 {
495     Name *name = function->pool->New<Name>();
496     name->init(base, type, function->newString(id),
497                Name::Property, line, column);
498     name->meta = meta;
499     name->property = property;
500     name->storage = storage;
501     return name;
502 }
503
504 Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QDeclarativePropertyData *property,
505                          quint32 line, quint32 column)
506 {
507     Name *name = function->pool->New<Name>();
508     name->init(base, type, function->newString(id),
509                Name::Property, line, column);
510     name->meta = meta;
511     name->property = property;
512     return name;
513 }
514
515 Name *BasicBlock::ID_OBJECT(const QString &id, const QDeclarativeScript::Object *object, quint32 line, quint32 column)
516 {
517     Name *name = function->pool->New<Name>();
518     name->init(/*base = */ 0, IR::ObjectType,
519                function->newString(id),
520                Name::IdObject, line, column);
521     name->idObject = object;
522     name->property = 0;
523     name->storage = Name::IdStorage;
524     return name;
525 }
526
527 Name *BasicBlock::ATTACH_TYPE(const QString &id, const QDeclarativeType *attachType, Name::Storage storage,
528                               quint32 line, quint32 column)
529
530     Name *name = function->pool->New<Name>();
531     name->init(/*base = */ 0, IR::AttachType,
532                function->newString(id),
533                Name::AttachType, line, column);
534     name->declarativeType = attachType;
535     name->storage = storage;
536     return name;
537 }
538
539
540 Expr *BasicBlock::UNOP(AluOp op, Expr *expr) 
541
542     Unop *e = function->pool->New<Unop>();
543     e->init(op, expr);
544     return e;
545 }
546
547 Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
548 {
549     if (left && right) {
550         if (Const *c1 = left->asConst()) {
551             if (Const *c2 = right->asConst()) {
552                 switch (op) {
553                 case OpAdd: return CONST(c1->value + c2->value);
554                 case OpAnd: return CONST(c1->value ? c2->value : 0);
555                 case OpBitAnd: return CONST(int(c1->value) & int(c2->value));
556                 case OpBitOr: return CONST(int(c1->value) | int(c2->value));
557                 case OpBitXor: return CONST(int(c1->value) ^ int(c2->value));
558                 case OpDiv: return CONST(c1->value / c2->value);
559                 case OpEqual: return CONST(c1->value == c2->value);
560                 case OpGe: return CONST(c1->value >= c2->value);
561                 case OpGt: return CONST(c1->value > c2->value);
562                 case OpLe: return CONST(c1->value <= c2->value);
563                 case OpLShift: return CONST(int(c1->value) << int(c2->value));
564                 case OpLt: return CONST(c1->value < c2->value);
565                 case OpMod: return CONST(::fmod(c1->value, c2->value));
566                 case OpMul: return CONST(c1->value * c2->value);
567                 case OpNotEqual: return CONST(c1->value != c2->value);
568                 case OpOr: return CONST(c1->value ? c1->value : c2->value);
569                 case OpRShift: return CONST(int(c1->value) >> int(c2->value));
570                 case OpStrictEqual: return CONST(c1->value == c2->value);
571                 case OpStrictNotEqual: return CONST(c1->value != c2->value);
572                 case OpSub: return CONST(c1->value - c2->value);
573                 case OpURShift: return CONST(unsigned(c1->value) >> int(c2->value));
574
575                 case OpIfTrue: // unary ops
576                 case OpNot:
577                 case OpUMinus:
578                 case OpUPlus:
579                 case OpCompl:
580                 case OpInvalid:
581                     break;
582                 }
583             }
584         }
585     }
586
587     Binop *e = function->pool->New<Binop>();
588     e->init(op, left, right);
589     return e;
590 }
591
592 Expr *BasicBlock::CALL(Expr *base, ExprList *args)
593
594     Call *e = function->pool->New<Call>();
595     e->init(base, args);
596     return e;
597 }
598
599 Stmt *BasicBlock::EXP(Expr *expr) 
600
601     Exp *s = function->pool->New<Exp>();
602     s->init(expr);
603     statements.append(s);
604     return s;
605 }
606
607 Stmt *BasicBlock::MOVE(Expr *target, Expr *source, bool isMoveForReturn) 
608
609     Move *s = function->pool->New<Move>();
610     s->init(target, source, isMoveForReturn);
611     statements.append(s);
612     return s;
613 }
614
615 Stmt *BasicBlock::JUMP(BasicBlock *target) 
616 {
617     if (isTerminated())
618         return 0;
619
620     Jump *s = function->pool->New<Jump>();
621     s->init(target);
622     statements.append(s);
623     return s;
624 }
625
626 Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse) 
627 {
628     if (isTerminated())
629         return 0;
630
631     CJump *s = function->pool->New<CJump>();
632     s->init(cond, iftrue, iffalse);
633     statements.append(s);
634     return s;
635 }
636
637 Stmt *BasicBlock::RET(Expr *expr, Type type, quint32 line, quint32 column)
638 {
639     if (isTerminated())
640         return 0;
641
642     Ret *s = function->pool->New<Ret>();
643     s->init(expr, type, line, column);
644     statements.append(s);
645     return s;
646 }
647
648 void BasicBlock::dump(QTextStream &out)
649 {
650     out << 'L' << this << ':' << endl;
651     foreach (Stmt *s, statements) {
652         out << '\t';
653         s->dump(out);
654         out << endl;
655     }
656 }
657
658 #ifdef DEBUG_IR_STRUCTURE
659
660 static const char *symbolname(Name::Symbol s) 
661 {
662     switch (s) {
663     case Name::Unbound:
664         return "Unbound";
665     case Name::IdObject:
666         return "IdObject";
667     case Name::AttachType:
668         return "AttachType";
669     case Name::Object:
670         return "Object";
671     case Name::Property:
672         return "Property";
673     case Name::Slot:
674         return "Slot";
675     default:
676         Q_ASSERT(!"Unreachable");
677         return "Unknown"; 
678     }
679 }
680
681 static const char *storagename(Name::Storage s)
682 {
683     switch (s) {
684     case Name::MemberStorage:
685         return "MemberStorage";
686     case Name::IdStorage:
687         return "IdStorage";
688     case Name::RootStorage:
689         return "RootStorage";
690     case Name::ScopeStorage:
691         return "ScopeStorage";
692     default:
693         Q_ASSERT(!"Unreachable");
694         return "UnknownStorage";
695     }
696 }
697
698 IRDump::IRDump()
699 : indentSize(0)
700 {
701 }
702
703 void IRDump::inc()
704 {
705     indentSize++;
706     indentData = QByteArray(indentSize * 4, ' ');
707 }
708
709 void IRDump::dec()
710 {
711     indentSize--;
712     indentData = QByteArray(indentSize * 4, ' ');
713 }
714
715 void IRDump::dec();
716
717 void IRDump::expression(QDeclarativeJS::IR::Expr *e)
718 {
719     inc();
720
721     e->accept(this);
722
723     dec();
724 }
725
726 void IRDump::basicblock(QDeclarativeJS::IR::BasicBlock *b)
727 {
728     inc();
729
730     qWarning().nospace() << indent() << "BasicBlock " << b << " {";
731     for (int ii = 0; ii < b->statements.count(); ++ii) {
732         statement(b->statements.at(ii));
733         if (ii != (b->statements.count() - 1))
734             qWarning();
735     }
736     qWarning().nospace() << indent() << "}";
737
738     dec();
739 }
740
741 void IRDump::statement(QDeclarativeJS::IR::Stmt *s)
742 {
743     inc();
744
745     s->accept(this);
746
747     dec();
748 }
749
750 void IRDump::function(QDeclarativeJS::IR::Function *f)
751 {
752     inc();
753
754     qWarning().nospace() << indent() << "Function {";
755     for (int ii = 0; ii < f->basicBlocks.count(); ++ii) {
756         basicblock(f->basicBlocks.at(ii));
757     }
758     qWarning().nospace() << indent() << "}";
759
760     dec();
761 }
762
763 const char *IRDump::indent()
764 {
765     return indentData.constData();
766 }
767
768 void IRDump::visitConst(QDeclarativeJS::IR::Const *e)
769 {
770     qWarning().nospace() << indent() << "Const:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
771 }
772
773 void IRDump::visitString(QDeclarativeJS::IR::String *e)
774 {
775     qWarning().nospace() << indent() << "String:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
776 }
777
778 static void namedumprecur(QDeclarativeJS::IR::Name *e, const char *indent) 
779 {
780     if (e->base) namedumprecur(e->base, indent);
781     qWarning().nospace() << indent << "    { type: " << typeName(e->type) << ", symbol: " << symbolname(e->symbol) << ", storage: " << storagename(e->storage) << ", id: " << e->id << "}";
782 }
783
784 void IRDump::visitName(QDeclarativeJS::IR::Name *e)
785 {
786     qWarning().nospace() << indent() << "Name:Expr {";
787     namedumprecur(e, indent());
788     qWarning().nospace() << indent() << "}";
789 }
790
791 void IRDump::visitTemp(QDeclarativeJS::IR::Temp *e)
792 {
793     qWarning().nospace() << indent() << "Temp:Expr { type: " << typeName(e->type) << ", index: " << e->index << " }";
794 }
795
796 void IRDump::visitUnop(QDeclarativeJS::IR::Unop *e)
797 {
798     qWarning().nospace() << indent() << "Unop:Expr { ";
799     qWarning().nospace() << indent() << "    type: " << typeName(e->type) << ", op: " << opname(e->op);
800     qWarning().nospace() << indent() << "    expr: {";
801     expression(e->expr);
802     qWarning().nospace() << indent() << "    }";
803     qWarning().nospace() << indent() << "}";
804 }
805
806 void IRDump::visitBinop(QDeclarativeJS::IR::Binop *e)
807 {
808     qWarning().nospace() << indent() << "Binop:Expr { ";
809     qWarning().nospace() << indent() << "    type: " << typeName(e->type) << ", op: " << opname(e->op);
810     qWarning().nospace() << indent() << "    left: {";
811     inc();
812     expression(e->left);
813     dec();
814     qWarning().nospace() << indent() << "    },";
815     qWarning().nospace() << indent() << "    right: {";
816     inc();
817     expression(e->right);
818     dec();
819     qWarning().nospace() << indent() << "    }";
820     qWarning().nospace() << indent() << "}";
821 }
822
823 void IRDump::visitCall(QDeclarativeJS::IR::Call *e)
824 {
825     Q_UNUSED(e);
826     qWarning().nospace() << indent() << "Exp::Call { }";
827 }
828
829 void IRDump::visitExp(QDeclarativeJS::IR::Exp *s)
830 {
831     qWarning().nospace() << indent() << "Exp:Stmt {";
832     expression(s->expr);
833     qWarning().nospace() << indent() << "}";
834 }
835
836 void IRDump::visitMove(QDeclarativeJS::IR::Move *s)
837 {
838     qWarning().nospace() << indent() << "Move:Stmt {";
839     qWarning().nospace() << indent() << "    isMoveForReturn: " << s->isMoveForReturn;
840     qWarning().nospace() << indent() << "    target: {";
841     inc();
842     expression(s->target);
843     dec();
844     qWarning().nospace() << indent() << "    },";
845     qWarning().nospace() << indent() << "    source: {";
846     inc();
847     expression(s->source);
848     dec();
849     qWarning().nospace() << indent() << "    }";
850     qWarning().nospace() << indent() << "}";
851 }
852
853 void IRDump::visitJump(QDeclarativeJS::IR::Jump *s)
854 {
855     qWarning().nospace() << indent() << "Jump:Stmt { BasicBlock(" << s->target << ") }";
856 }
857
858 void IRDump::visitCJump(QDeclarativeJS::IR::CJump *s)
859 {
860     qWarning().nospace() << indent() << "CJump:Stmt {";
861     qWarning().nospace() << indent() << "    cond: {";
862     inc();
863     expression(s->cond);
864     dec();
865     qWarning().nospace() << indent() << "    }";
866     qWarning().nospace() << indent() << "    iftrue: BasicBlock(" << s->iftrue << ")";
867     qWarning().nospace() << indent() << "    iffalse: BasicBlock(" << s->iffalse << ")";
868     qWarning().nospace() << indent() << "}";
869 }
870
871 void IRDump::visitRet(QDeclarativeJS::IR::Ret *s)
872 {
873     qWarning().nospace() << indent() << "Ret:Stmt {";
874     qWarning().nospace() << indent() << "    type: " << typeName(s->type);
875     expression(s->expr);
876     qWarning().nospace() << indent() << "}";
877 }
878 #endif
879
880 } // end of namespace IR
881 } // end of namespace QDeclarativeJS
882
883 QT_END_NAMESPACE