]>
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 CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
447 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
448 object_
->Output(out
, Precedence(), CYLeft(flags
));
449 if (const char *word
= property_
->Word())
452 out
<< "->" << '[' << *property_
<< ']';
455 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
456 const char *name(Operator());
457 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
460 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
461 lhs_
->Output(out
, Precedence(), left
);
462 out
<< ' ' << name
<< ' ';
463 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
464 rhs_
->Output(out
, Precedence() - 1, right
);
469 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
470 out
<< *name_
<< ':' << ' ';
471 statement_
->Single(out
, CYRight(flags
));
474 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
475 next_
->Output(out
, Precedence(), identifier
);
481 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
483 next_
->Output(out
, Precedence(), identifier
);
484 out
<< ')' << '(' << parameters_
<< ')';
487 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
489 next_
->Output(out
, Precedence(), identifier
);
492 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
493 next_
->Output(out
, Precedence(), identifier
);
494 out
<< '(' << parameters_
<< ')';
497 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
499 next_
->Output(out
, Precedence(), identifier
);
502 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
504 next_
->Output(out
, Precedence(), identifier
);
507 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
513 bool protect(precedence
> Precedence());
517 Output(out
, identifier
);
522 void CYTypedIdentifier::Output(CYOutput
&out
) const {
523 specifier_
->Output(out
);
524 modifier_
->Output(out
, 0, identifier_
);
527 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
528 out
<< "@encode(" << typed_
<< ")";
531 void CYTypedParameter::Output(CYOutput
&out
) const {
534 out
<< ',' << ' ' << next_
;
537 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
538 // XXX: this is seriously wrong
545 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
546 out
<< "typedef" << *typed_
;
549 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
550 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
551 code_
->Single(out
, CYRight(flags
));
554 void CYModule::Output(CYOutput
&out
) const {
563 void New::Output(CYOutput
&out
, CYFlags flags
) const {
565 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
566 constructor_
->Output(out
, Precedence(), jacks
);
567 if (arguments_
!= NULL
)
568 out
<< '(' << *arguments_
<< ')';
573 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
577 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
578 std::ostringstream str
;
579 CYNumerify(str
, Value());
580 std::string
value(str
.str());
581 out
<< value
.c_str();
582 // XXX: this should probably also handle hex conversions and exponents
583 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
587 void CYNumber::PropertyName(CYOutput
&out
) const {
588 Output(out
, CYNoFlags
);
591 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
592 bool protect((flags
& CYNoBrace
) != 0);
604 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
605 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
609 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
610 const char *name(Operator());
614 rhs_
->Output(out
, Precedence(), CYRight(flags
));
617 void CYProgram::Output(CYOutput
&out
) const {
618 if (statements_
!= NULL
)
619 statements_
->Multiple(out
);
622 void CYProperty::Output(CYOutput
&out
) const {
624 name_
->PropertyName(out
);
626 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
628 out
<< ',' << '\n' << *next_
;
633 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
637 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
640 out
<< ' ' << *value_
;
644 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
645 call_
->Output(out
, CYLeft(flags
));
647 proc_
->Output(out
, CYRight(flags
));
650 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
651 // XXX: this is not outputting the parameters
655 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
657 CYForEach (next
, this) {
658 bool last(next
->next_
== NULL
);
659 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
662 next
->Output(out
, jacks
);
667 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
669 return out
.Terminate();
671 _assert(next_
== NULL
);
680 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
681 std::ostringstream str
;
682 CYStringify(str
, value_
, size_
);
683 out
<< str
.str().c_str();
686 void CYString::PropertyName(CYOutput
&out
) const {
687 if (const char *word
= Word())
693 static const char *Reserved_
[] = {
694 "false", "null", "true",
696 "break", "case", "catch", "continue", "default",
697 "delete", "do", "else", "finally", "for", "function",
698 "if", "in", "instanceof", "new", "return", "switch",
699 "this", "throw", "try", "typeof", "var", "void",
704 "class", "enum", "export", "extends", "import", "super",
706 "abstract", "boolean", "byte", "char", "double", "final",
707 "float", "goto", "int", "long", "native", "short",
708 "synchronized", "throws", "transient", "volatile",
715 const char *CYString::Word() const {
716 if (size_
== 0 || !WordStartRange_
[value_
[0]])
718 for (size_t i(1); i
!= size_
; ++i
)
719 if (!WordEndRange_
[value_
[i
]])
721 const char *value(Value());
722 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
723 if (strcmp(*reserved
, value
) == 0)
728 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
729 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
734 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
741 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
744 out
<< ' ' << *value_
;
748 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
749 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
754 void CYTypeError::Output(CYOutput
&out
) const {
758 void CYTypeLong::Output(CYOutput
&out
) const {
759 out
<< "long" << specifier_
;
762 void CYTypeShort::Output(CYOutput
&out
) const {
763 out
<< "short" << specifier_
;
766 void CYTypeSigned::Output(CYOutput
&out
) const {
767 out
<< "signed" << specifier_
;
770 void CYTypeUnsigned::Output(CYOutput
&out
) const {
771 out
<< "unsigned" << specifier_
;
774 void CYTypeVariable::Output(CYOutput
&out
) const {
778 void CYTypeVoid::Output(CYOutput
&out
) const {
782 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
784 declarations_
->Output(out
, flags
);
788 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
792 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
793 out
<< "while" << '(' << *test_
<< ')';
794 code_
->Single(out
, CYRight(flags
));
797 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
798 out
<< "with" << '(' << *scope_
<< ')';
799 code_
->Single(out
, CYRight(flags
));
802 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
804 out
<< "objc_getClass(";
805 out
<< '"' << Word() << '"';
810 void CYWord::Output(CYOutput
&out
) const {
812 if (out
.options_
.verbose_
)
813 out
.out_
<< '@' << this;
816 void CYWord::PropertyName(CYOutput
&out
) const {
820 const char *CYWord::Word() const {