]>
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
);
121 if (next_
->name_
== NULL
)
123 out
<< ' ' << *next_
;
127 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
128 out
<< '[' << elements_
<< ']';
131 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
132 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
135 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
136 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
137 out
<< ' ' << Operator() << ' ';
138 rhs_
->Output(out
, Precedence(), CYRight(flags
));
141 void CYBlock::Output(CYOutput
&out
) const {
144 if (statements_
!= NULL
)
145 statements_
->Multiple(out
);
150 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
151 if (statements_
== NULL
)
153 else if (statements_
->next_
== NULL
)
154 statements_
->Single(out
, flags
);
159 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
160 out
<< (Value() ? "true" : "false");
163 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
166 out
<< ' ' << *label_
;
170 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
171 bool protect((flags
& CYNoCall
) != 0);
174 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
175 out
<< '(' << arguments_
<< ')';
183 void Catch::Output(CYOutput
&out
) const {
184 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ' << code_
;
189 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
196 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
198 expression_
->Output(out
, flags
);
200 expression_
->Output(out
, CYLeft(flags
));
202 next_
->Output(out
, CYRight(flags
));
206 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
207 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
208 out
<< ' ' << '?' << ' ';
210 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
211 out
<< ' ' << ':' << ' ';
212 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
215 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
218 out
<< ' ' << *label_
;
222 void CYClause::Output(CYOutput
&out
) const {
224 out
<< "case" << ' ' << *case_
;
228 if (statements_
!= NULL
)
229 statements_
->Multiple(out
);
233 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
234 out
<< "debugger" << ';';
237 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
239 Output(out
, CYRight(flags
));
242 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
244 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
245 if (initialiser_
!= NULL
) {
246 out
<< ' ' << '=' << ' ';
247 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
251 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
253 Output(out
, CYRight(flags
));
256 void CYDeclarations::Output(CYOutput
&out
) const {
257 Output(out
, CYNoFlags
);
260 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
261 const CYDeclarations
*declaration(this);
265 CYDeclarations
*next(declaration
->next_
);
267 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
269 declaration
->declaration_
->Output(out
, jacks
);
279 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
280 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
281 if (const char *word
= property_
->Word())
284 out
<< '[' << *property_
<< ']';
287 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
289 code_
->Single(out
, CYCenter(flags
));
290 out
<< "while" << ' ' << '(' << *test_
<< ')';
293 void CYElement::Output(CYOutput
&out
) const {
295 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
296 if (next_
!= NULL
|| value_
== NULL
) {
298 if (next_
!= NULL
&& next_
->value_
!= NULL
)
305 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
309 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
310 expression_
->Output(out
, flags
| CYNoBF
);
314 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
315 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
318 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
319 Output(out
, flags
| CYNoRightHand
);
322 void CYExpression::Output(CYOutput
&out
) const {
323 Output(out
, CYNoFlags
);
326 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
327 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
328 out
<< '(' << *this << ')';
333 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
334 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << code_
;
337 void CYFinally::Output(CYOutput
&out
) const {
338 out
<< ' ' << "finally" << ' ' << code_
;
341 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
342 out
<< "for" << ' ' << '(';
343 if (initialiser_
!= NULL
)
344 initialiser_
->Output(out
, CYNoIn
);
350 if (increment_
!= NULL
)
354 code_
->Single(out
, CYRight(flags
));
357 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
358 out
<< "for" << ' ' << "each" << ' ' << '(';
359 initialiser_
->ForIn(out
, CYNoIn
);
360 out
<< "in" << *set_
<< ')';
361 code_
->Single(out
, CYRight(flags
));
364 void CYForOfComprehension::Output(CYOutput
&out
) const {
365 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
368 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
369 out
<< "for" << ' ' << '(';
370 if (initialiser_
!= NULL
)
371 initialiser_
->ForIn(out
, CYNoIn
);
372 out
<< "in" << *set_
<< ')';
373 code_
->Single(out
, CYRight(flags
));
376 void CYForInComprehension::Output(CYOutput
&out
) const {
377 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
380 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
381 // XXX: one could imagine using + here to save a byte
382 bool protect((flags
& CYNoFunction
) != 0);
387 out
<< ' ' << *name_
;
388 out
<< '(' << parameters_
<< ')';
394 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
395 CYFunction::Output(out
, flags
);
398 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
399 CYFunction::Output(out
, flags
);
402 void CYFunctionParameter::Output(CYOutput
&out
) const {
403 initialiser_
->Output(out
, CYNoFlags
);
405 out
<< ',' << ' ' << *next_
;
408 const char *CYIdentifier::Word() const {
409 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
412 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
414 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
419 out
<< "if" << ' ' << '(' << *test_
<< ')';
421 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
423 CYFlags
jacks(CYNoDangle
);
427 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
429 true_
->Single(out
, jacks
);
431 if (false_
!= NULL
) {
432 out
<< '\t' << "else";
433 false_
->Single(out
, right
);
440 void CYIfComprehension::Output(CYOutput
&out
) const {
441 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
444 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
445 object_
->Output(out
, Precedence(), CYLeft(flags
));
446 if (const char *word
= property_
->Word())
449 out
<< "->" << '[' << *property_
<< ']';
452 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
453 const char *name(Operator());
454 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
457 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
458 lhs_
->Output(out
, Precedence(), left
);
459 out
<< ' ' << name
<< ' ';
460 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
461 rhs_
->Output(out
, Precedence() - 1, right
);
466 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
467 out
<< *name_
<< ':' << ' ';
468 statement_
->Single(out
, CYRight(flags
));
471 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
472 next_
->Output(out
, Precedence(), identifier
);
478 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
480 next_
->Output(out
, Precedence(), identifier
);
481 out
<< ')' << '(' << parameters_
<< ')';
484 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
486 next_
->Output(out
, Precedence(), identifier
);
489 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
490 next_
->Output(out
, Precedence(), identifier
);
491 out
<< '(' << parameters_
<< ')';
494 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
496 next_
->Output(out
, Precedence(), identifier
);
499 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
501 next_
->Output(out
, Precedence(), identifier
);
504 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
510 bool protect(precedence
> Precedence());
514 Output(out
, identifier
);
519 void CYTypedIdentifier::Output(CYOutput
&out
) const {
520 specifier_
->Output(out
);
521 modifier_
->Output(out
, 0, identifier_
);
524 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
525 out
<< "@encode(" << typed_
<< ")";
528 void CYTypedParameter::Output(CYOutput
&out
) const {
531 out
<< ',' << ' ' << next_
;
534 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
535 // XXX: this is seriously wrong
542 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
543 out
<< "typedef" << *typed_
;
546 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
547 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
548 code_
->Single(out
, CYRight(flags
));
554 void New::Output(CYOutput
&out
, CYFlags flags
) const {
556 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
557 constructor_
->Output(out
, Precedence(), jacks
);
558 if (arguments_
!= NULL
)
559 out
<< '(' << *arguments_
<< ')';
564 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
568 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
569 std::ostringstream str
;
570 CYNumerify(str
, Value());
571 std::string
value(str
.str());
572 out
<< value
.c_str();
573 // XXX: this should probably also handle hex conversions and exponents
574 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
578 void CYNumber::PropertyName(CYOutput
&out
) const {
579 Output(out
, CYNoFlags
);
582 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
583 bool protect((flags
& CYNoBrace
) != 0);
595 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
596 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
600 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
601 const char *name(Operator());
605 rhs_
->Output(out
, Precedence(), CYRight(flags
));
608 void CYProgram::Output(CYOutput
&out
) const {
609 if (statements_
!= NULL
)
610 statements_
->Multiple(out
);
613 void CYProperty::Output(CYOutput
&out
) const {
615 name_
->PropertyName(out
);
617 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
619 out
<< ',' << '\n' << *next_
;
624 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
628 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
631 out
<< ' ' << *value_
;
635 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
636 call_
->Output(out
, CYLeft(flags
));
638 proc_
->Output(out
, CYRight(flags
));
641 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
642 // XXX: this is not outputting the parameters
646 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
648 CYForEach (next
, this) {
649 bool last(next
->next_
== NULL
);
650 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
653 next
->Output(out
, jacks
);
658 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
660 return out
.Terminate();
662 _assert(next_
== NULL
);
671 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
672 std::ostringstream str
;
673 CYStringify(str
, value_
, size_
);
674 out
<< str
.str().c_str();
677 void CYString::PropertyName(CYOutput
&out
) const {
678 if (const char *word
= Word())
684 static const char *Reserved_
[] = {
685 "false", "null", "true",
687 "break", "case", "catch", "continue", "default",
688 "delete", "do", "else", "finally", "for", "function",
689 "if", "in", "instanceof", "new", "return", "switch",
690 "this", "throw", "try", "typeof", "var", "void",
695 "class", "enum", "export", "extends", "import", "super",
697 "abstract", "boolean", "byte", "char", "double", "final",
698 "float", "goto", "int", "long", "native", "short",
699 "synchronized", "throws", "transient", "volatile",
706 const char *CYString::Word() const {
707 if (size_
== 0 || !WordStartRange_
[value_
[0]])
709 for (size_t i(1); i
!= size_
; ++i
)
710 if (!WordEndRange_
[value_
[i
]])
712 const char *value(Value());
713 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
714 if (strcmp(*reserved
, value
) == 0)
719 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
720 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
725 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
732 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
735 out
<< ' ' << *value_
;
739 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
740 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
745 void CYTypeError::Output(CYOutput
&out
) const {
749 void CYTypeLong::Output(CYOutput
&out
) const {
750 out
<< "long" << specifier_
;
753 void CYTypeShort::Output(CYOutput
&out
) const {
754 out
<< "short" << specifier_
;
757 void CYTypeSigned::Output(CYOutput
&out
) const {
758 out
<< "signed" << specifier_
;
761 void CYTypeUnsigned::Output(CYOutput
&out
) const {
762 out
<< "unsigned" << specifier_
;
765 void CYTypeVariable::Output(CYOutput
&out
) const {
769 void CYTypeVoid::Output(CYOutput
&out
) const {
773 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
775 declarations_
->Output(out
, flags
);
779 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
783 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
784 out
<< "while" << '(' << *test_
<< ')';
785 code_
->Single(out
, CYRight(flags
));
788 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
789 out
<< "with" << '(' << *scope_
<< ')';
790 code_
->Single(out
, CYRight(flags
));
793 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
795 out
<< "objc_getClass(";
796 out
<< '"' << Word() << '"';
801 void CYWord::Output(CYOutput
&out
) const {
803 if (out
.options_
.verbose_
)
804 out
.out_
<< '@' << this;
807 void CYWord::PropertyName(CYOutput
&out
) const {
811 const char *CYWord::Word() const {