]>
git.saurik.com Git - cycript.git/blob - Output.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2013 Jay Freeman (saurik)
5 /* GNU General Public License, Version 3 {{{ */
7 * Cycript is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 3 of the License,
10 * or (at your option) any later version.
12 * Cycript is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
22 #include "cycript.hpp"
27 void CYOutput::Terminate() {
32 CYOutput
&CYOutput::operator <<(char rhs
) {
33 if (rhs
== ' ' || rhs
== '\n')
39 for (unsigned i(0); i
!= indent_
; ++i
)
42 else if (rhs
== '\r') {
54 if (mode_
== Terminated
&& rhs
!= '}') {
66 } else if (rhs
== '+') {
70 } else if (rhs
== '-') {
71 if (mode_
== NoHyphen
)
74 } else if (WordEndRange_
[rhs
]) {
75 if (mode_
== NoLetter
)
87 CYOutput
&CYOutput::operator <<(const char *rhs
) {
88 size_t size(strlen(rhs
));
93 if (mode_
== Terminated
)
96 mode_
== NoPlus
&& *rhs
== '+' ||
97 mode_
== NoHyphen
&& *rhs
== '-' ||
98 mode_
== NoLetter
&& WordEndRange_
[*rhs
]
102 if (WordEndRange_
[rhs
[size
- 1]])
112 void CYArgument::Output(CYOutput
&out
) const {
119 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
122 out
<< ' ' << *next_
;
126 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
127 out
<< '[' << elements_
<< ']';
130 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
131 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
134 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
135 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
136 out
<< ' ' << Operator() << ' ';
137 rhs_
->Output(out
, Precedence(), CYRight(flags
));
140 void CYBlock::Output(CYOutput
&out
) const {
143 if (statements_
!= NULL
)
144 statements_
->Multiple(out
);
149 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
150 if (statements_
== NULL
)
152 else if (statements_
->next_
== NULL
)
153 statements_
->Single(out
, flags
);
158 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
159 out
<< (Value() ? "true" : "false");
162 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
165 out
<< ' ' << *label_
;
169 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
170 bool protect((flags
& CYNoCall
) != 0);
173 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
174 out
<< '(' << arguments_
<< ')';
182 void Catch::Output(CYOutput
&out
) const {
183 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ' << code_
;
188 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
195 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
197 expression_
->Output(out
, flags
);
199 expression_
->Output(out
, CYLeft(flags
));
201 next_
->Output(out
, CYRight(flags
));
205 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
206 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
207 out
<< ' ' << '?' << ' ';
209 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
210 out
<< ' ' << ':' << ' ';
211 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
214 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
217 out
<< ' ' << *label_
;
221 void CYClause::Output(CYOutput
&out
) const {
223 out
<< "case" << ' ' << *case_
;
227 if (statements_
!= NULL
)
228 statements_
->Multiple(out
);
232 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
233 out
<< "debugger" << ';';
236 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
238 Output(out
, CYRight(flags
));
241 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
243 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
244 if (initialiser_
!= NULL
) {
245 out
<< ' ' << '=' << ' ';
246 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
250 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
252 Output(out
, CYRight(flags
));
255 void CYDeclarations::Output(CYOutput
&out
) const {
256 Output(out
, CYNoFlags
);
259 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
260 const CYDeclarations
*declaration(this);
264 CYDeclarations
*next(declaration
->next_
);
266 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
268 declaration
->declaration_
->Output(out
, jacks
);
278 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
279 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
280 if (const char *word
= property_
->Word())
283 out
<< '[' << *property_
<< ']';
286 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
288 code_
->Single(out
, CYCenter(flags
));
289 out
<< "while" << ' ' << '(' << *test_
<< ')';
292 void CYElement::Output(CYOutput
&out
) const {
294 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
295 if (next_
!= NULL
|| value_
== NULL
) {
297 if (next_
!= NULL
&& next_
->value_
!= NULL
)
304 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
308 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
309 expression_
->Output(out
, flags
| CYNoBF
);
313 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
314 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
317 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
318 Output(out
, flags
| CYNoRightHand
);
321 void CYExpression::Output(CYOutput
&out
) const {
322 Output(out
, CYNoFlags
);
325 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
326 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
327 out
<< '(' << *this << ')';
332 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
333 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << code_
;
336 void CYFinally::Output(CYOutput
&out
) const {
337 out
<< ' ' << "finally" << ' ' << code_
;
340 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
341 out
<< "for" << ' ' << '(';
342 if (initialiser_
!= NULL
)
343 initialiser_
->Output(out
, CYNoIn
);
349 if (increment_
!= NULL
)
353 code_
->Single(out
, CYRight(flags
));
356 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
357 out
<< "for" << ' ' << "each" << ' ' << '(';
358 initialiser_
->ForIn(out
, CYNoIn
);
359 out
<< "in" << *set_
<< ')';
360 code_
->Single(out
, CYRight(flags
));
363 void CYForOfComprehension::Output(CYOutput
&out
) const {
364 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
367 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
368 out
<< "for" << ' ' << '(';
369 if (initialiser_
!= NULL
)
370 initialiser_
->ForIn(out
, CYNoIn
);
371 out
<< "in" << *set_
<< ')';
372 code_
->Single(out
, CYRight(flags
));
375 void CYForInComprehension::Output(CYOutput
&out
) const {
376 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
379 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
380 // XXX: one could imagine using + here to save a byte
381 bool protect((flags
& CYNoFunction
) != 0);
386 out
<< ' ' << *name_
;
387 out
<< '(' << parameters_
<< ')';
393 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
394 CYFunction::Output(out
, flags
);
397 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
398 CYFunction::Output(out
, flags
);
401 void CYFunctionParameter::Output(CYOutput
&out
) const {
402 initialiser_
->Output(out
, CYNoFlags
);
404 out
<< ',' << ' ' << *next_
;
407 const char *CYIdentifier::Word() const {
408 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
411 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
413 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
418 out
<< "if" << ' ' << '(' << *test_
<< ')';
420 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
422 CYFlags
jacks(CYNoDangle
);
426 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
428 true_
->Single(out
, jacks
);
430 if (false_
!= NULL
) {
431 out
<< '\t' << "else";
432 false_
->Single(out
, right
);
439 void CYIfComprehension::Output(CYOutput
&out
) const {
440 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
443 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
444 object_
->Output(out
, Precedence(), CYLeft(flags
));
445 if (const char *word
= property_
->Word())
448 out
<< "->" << '[' << *property_
<< ']';
451 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
452 const char *name(Operator());
453 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
456 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
457 lhs_
->Output(out
, Precedence(), left
);
458 out
<< ' ' << name
<< ' ';
459 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
460 rhs_
->Output(out
, Precedence() - 1, right
);
465 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
466 out
<< *name_
<< ':' << ' ';
467 statement_
->Single(out
, CYRight(flags
));
470 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
471 next_
->Output(out
, Precedence(), identifier
);
477 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
479 next_
->Output(out
, Precedence(), identifier
);
480 out
<< ')' << '(' << parameters_
<< ')';
483 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
485 next_
->Output(out
, Precedence(), identifier
);
488 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
489 next_
->Output(out
, Precedence(), identifier
);
490 out
<< '(' << parameters_
<< ')';
493 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
495 next_
->Output(out
, Precedence(), identifier
);
498 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
500 next_
->Output(out
, Precedence(), identifier
);
503 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
509 bool protect(precedence
> Precedence());
513 Output(out
, identifier
);
518 void CYTypedIdentifier::Output(CYOutput
&out
) const {
519 specifier_
->Output(out
);
520 modifier_
->Output(out
, 0, identifier_
);
523 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
524 out
<< "@encode(" << typed_
<< ")";
527 void CYTypedParameter::Output(CYOutput
&out
) const {
530 out
<< ',' << ' ' << next_
;
533 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
534 // XXX: this is seriously wrong
541 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
542 out
<< "typedef" << *typed_
;
545 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
546 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
547 code_
->Single(out
, CYRight(flags
));
553 void New::Output(CYOutput
&out
, CYFlags flags
) const {
555 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
556 constructor_
->Output(out
, Precedence(), jacks
);
557 if (arguments_
!= NULL
)
558 out
<< '(' << *arguments_
<< ')';
563 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
567 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
568 std::ostringstream str
;
569 CYNumerify(str
, Value());
570 std::string
value(str
.str());
571 out
<< value
.c_str();
572 // XXX: this should probably also handle hex conversions and exponents
573 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
577 void CYNumber::PropertyName(CYOutput
&out
) const {
578 Output(out
, CYNoFlags
);
581 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
582 bool protect((flags
& CYNoBrace
) != 0);
594 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
595 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
599 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
600 const char *name(Operator());
604 rhs_
->Output(out
, Precedence(), CYRight(flags
));
607 void CYProgram::Output(CYOutput
&out
) const {
608 if (statements_
!= NULL
)
609 statements_
->Multiple(out
);
612 void CYProperty::Output(CYOutput
&out
) const {
614 name_
->PropertyName(out
);
616 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
618 out
<< ',' << '\n' << *next_
;
623 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
627 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
630 out
<< ' ' << *value_
;
634 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
635 call_
->Output(out
, CYLeft(flags
));
637 proc_
->Output(out
, CYRight(flags
));
640 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
641 // XXX: this is not outputting the parameters
645 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
647 CYForEach (next
, this) {
648 bool last(next
->next_
== NULL
);
649 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
652 next
->Output(out
, jacks
);
657 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
659 return out
.Terminate();
661 _assert(next_
== NULL
);
670 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
671 std::ostringstream str
;
672 CYStringify(str
, value_
, size_
);
673 out
<< str
.str().c_str();
676 void CYString::PropertyName(CYOutput
&out
) const {
677 if (const char *word
= Word())
683 static const char *Reserved_
[] = {
684 "false", "null", "true",
686 "break", "case", "catch", "continue", "default",
687 "delete", "do", "else", "finally", "for", "function",
688 "if", "in", "instanceof", "new", "return", "switch",
689 "this", "throw", "try", "typeof", "var", "void",
694 "class", "enum", "export", "extends", "import", "super",
696 "abstract", "boolean", "byte", "char", "double", "final",
697 "float", "goto", "int", "long", "native", "short",
698 "synchronized", "throws", "transient", "volatile",
705 const char *CYString::Word() const {
706 if (size_
== 0 || !WordStartRange_
[value_
[0]])
708 for (size_t i(1); i
!= size_
; ++i
)
709 if (!WordEndRange_
[value_
[i
]])
711 const char *value(Value());
712 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
713 if (strcmp(*reserved
, value
) == 0)
718 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
719 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
724 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
731 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
734 out
<< ' ' << *value_
;
738 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
739 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
744 void CYTypeError::Output(CYOutput
&out
) const {
748 void CYTypeLong::Output(CYOutput
&out
) const {
749 out
<< "long" << specifier_
;
752 void CYTypeShort::Output(CYOutput
&out
) const {
753 out
<< "short" << specifier_
;
756 void CYTypeSigned::Output(CYOutput
&out
) const {
757 out
<< "signed" << specifier_
;
760 void CYTypeUnsigned::Output(CYOutput
&out
) const {
761 out
<< "unsigned" << specifier_
;
764 void CYTypeVariable::Output(CYOutput
&out
) const {
768 void CYTypeVoid::Output(CYOutput
&out
) const {
772 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
774 declarations_
->Output(out
, flags
);
778 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
782 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
783 out
<< "while" << '(' << *test_
<< ')';
784 code_
->Single(out
, CYRight(flags
));
787 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
788 out
<< "with" << '(' << *scope_
<< ')';
789 code_
->Single(out
, CYRight(flags
));
792 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
794 out
<< "objc_getClass(";
795 out
<< '"' << Word() << '"';
800 void CYWord::Output(CYOutput
&out
) const {
802 if (out
.options_
.verbose_
)
803 out
.out_
<< '@' << this;
806 void CYWord::PropertyName(CYOutput
&out
) const {
810 const char *CYWord::Word() const {