]>
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 {
197 if (CYExpression
*expression
= expressions_
)
198 if (CYExpression
*next
= expression
->next_
) {
199 expression
->Output(out
, CYLeft(flags
));
200 CYFlags
center(CYCenter(flags
));
201 while (next
!= NULL
) {
204 next
= expression
->next_
;
205 CYFlags
right(next
!= NULL
? center
: CYRight(flags
));
206 expression
->Output(out
, right
);
209 expression
->Output(out
, flags
);
212 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
213 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
214 out
<< ' ' << '?' << ' ';
216 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
217 out
<< ' ' << ':' << ' ';
218 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
221 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
224 out
<< ' ' << *label_
;
228 void CYClause::Output(CYOutput
&out
) const {
230 out
<< "case" << ' ' << *case_
;
234 if (statements_
!= NULL
)
235 statements_
->Multiple(out
);
239 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
240 out
<< "debugger" << ';';
243 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
245 Output(out
, CYRight(flags
));
248 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
250 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
251 if (initialiser_
!= NULL
) {
252 out
<< ' ' << '=' << ' ';
253 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
257 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
259 Output(out
, CYRight(flags
));
262 void CYDeclarations::Output(CYOutput
&out
) const {
263 Output(out
, CYNoFlags
);
266 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
267 const CYDeclarations
*declaration(this);
271 CYDeclarations
*next(declaration
->next_
);
273 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
275 declaration
->declaration_
->Output(out
, jacks
);
285 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
286 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
287 if (const char *word
= property_
->Word())
290 out
<< '[' << *property_
<< ']';
293 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
295 code_
->Single(out
, CYCenter(flags
));
296 out
<< "while" << ' ' << '(' << *test_
<< ')';
299 void CYElement::Output(CYOutput
&out
) const {
301 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
302 if (next_
!= NULL
|| value_
== NULL
) {
304 if (next_
!= NULL
&& next_
->value_
!= NULL
)
311 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
315 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
316 expression_
->Output(out
, flags
| CYNoBF
);
320 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
321 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
324 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
325 Output(out
, flags
| CYNoRightHand
);
328 void CYExpression::Output(CYOutput
&out
) const {
329 Output(out
, CYNoFlags
);
332 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
333 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
334 out
<< '(' << *this << ')';
339 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
340 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << code_
;
343 void CYFinally::Output(CYOutput
&out
) const {
344 out
<< ' ' << "finally" << ' ' << code_
;
347 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
348 out
<< "for" << ' ' << '(';
349 if (initialiser_
!= NULL
)
350 initialiser_
->Output(out
, CYNoIn
);
356 if (increment_
!= NULL
)
360 code_
->Single(out
, CYRight(flags
));
363 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
364 out
<< "for" << ' ' << "each" << ' ' << '(';
365 initialiser_
->ForIn(out
, CYNoIn
);
366 out
<< "in" << *set_
<< ')';
367 code_
->Single(out
, CYRight(flags
));
370 void CYForOfComprehension::Output(CYOutput
&out
) const {
371 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
374 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
375 out
<< "for" << ' ' << '(';
376 if (initialiser_
!= NULL
)
377 initialiser_
->ForIn(out
, CYNoIn
);
378 out
<< "in" << *set_
<< ')';
379 code_
->Single(out
, CYRight(flags
));
382 void CYForInComprehension::Output(CYOutput
&out
) const {
383 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
386 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
387 // XXX: one could imagine using + here to save a byte
388 bool protect((flags
& CYNoFunction
) != 0);
393 out
<< ' ' << *name_
;
394 out
<< '(' << parameters_
<< ')';
400 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
401 CYFunction::Output(out
, flags
);
404 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
405 CYFunction::Output(out
, flags
);
408 void CYFunctionParameter::Output(CYOutput
&out
) const {
409 initialiser_
->Output(out
, CYNoFlags
);
411 out
<< ',' << ' ' << *next_
;
414 const char *CYIdentifier::Word() const {
415 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
418 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
420 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
425 out
<< "if" << ' ' << '(' << *test_
<< ')';
427 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
429 CYFlags
jacks(CYNoDangle
);
433 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
435 true_
->Single(out
, jacks
);
437 if (false_
!= NULL
) {
438 out
<< '\t' << "else";
439 false_
->Single(out
, right
);
446 void CYIfComprehension::Output(CYOutput
&out
) const {
447 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
450 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
451 object_
->Output(out
, Precedence(), CYLeft(flags
));
452 if (const char *word
= property_
->Word())
455 out
<< "->" << '[' << *property_
<< ']';
458 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
459 const char *name(Operator());
460 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
463 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
464 lhs_
->Output(out
, Precedence(), left
);
465 out
<< ' ' << name
<< ' ';
466 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
467 rhs_
->Output(out
, Precedence() - 1, right
);
472 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
473 out
<< *name_
<< ':' << ' ';
474 statement_
->Single(out
, CYRight(flags
));
477 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
478 next_
->Output(out
, Precedence(), identifier
);
484 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
486 next_
->Output(out
, Precedence(), identifier
);
487 out
<< ')' << '(' << parameters_
<< ')';
490 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
492 next_
->Output(out
, Precedence(), identifier
);
495 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
496 next_
->Output(out
, Precedence(), identifier
);
497 out
<< '(' << parameters_
<< ')';
500 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
502 next_
->Output(out
, Precedence(), identifier
);
505 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
507 next_
->Output(out
, Precedence(), identifier
);
510 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
516 bool protect(precedence
> Precedence());
520 Output(out
, identifier
);
525 void CYTypedIdentifier::Output(CYOutput
&out
) const {
526 specifier_
->Output(out
);
527 modifier_
->Output(out
, 0, identifier_
);
530 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
531 out
<< "@encode(" << typed_
<< ")";
534 void CYTypedParameter::Output(CYOutput
&out
) const {
537 out
<< ',' << ' ' << next_
;
540 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
541 // XXX: this is seriously wrong
548 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
549 out
<< "typedef" << *typed_
;
552 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
553 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
554 code_
->Single(out
, CYRight(flags
));
560 void New::Output(CYOutput
&out
, CYFlags flags
) const {
562 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
563 constructor_
->Output(out
, Precedence(), jacks
);
564 if (arguments_
!= NULL
)
565 out
<< '(' << *arguments_
<< ')';
570 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
574 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
575 std::ostringstream str
;
576 CYNumerify(str
, Value());
577 std::string
value(str
.str());
578 out
<< value
.c_str();
579 // XXX: this should probably also handle hex conversions and exponents
580 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
584 void CYNumber::PropertyName(CYOutput
&out
) const {
585 Output(out
, CYNoFlags
);
588 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
589 bool protect((flags
& CYNoBrace
) != 0);
601 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
602 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
606 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
607 const char *name(Operator());
611 rhs_
->Output(out
, Precedence(), CYRight(flags
));
614 void CYProgram::Output(CYOutput
&out
) const {
615 if (statements_
!= NULL
)
616 statements_
->Multiple(out
);
619 void CYProperty::Output(CYOutput
&out
) const {
621 name_
->PropertyName(out
);
623 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
625 out
<< ',' << '\n' << *next_
;
630 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
634 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
637 out
<< ' ' << *value_
;
641 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
642 call_
->Output(out
, CYLeft(flags
));
644 proc_
->Output(out
, CYRight(flags
));
647 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
648 // XXX: this is not outputting the parameters
652 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
654 CYForEach (next
, this) {
655 bool last(next
->next_
== NULL
);
656 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
659 next
->Output(out
, jacks
);
664 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
666 return out
.Terminate();
668 _assert(next_
== NULL
);
677 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
678 std::ostringstream str
;
679 CYStringify(str
, value_
, size_
);
680 out
<< str
.str().c_str();
683 void CYString::PropertyName(CYOutput
&out
) const {
684 if (const char *word
= Word())
690 static const char *Reserved_
[] = {
691 "false", "null", "true",
693 "break", "case", "catch", "continue", "default",
694 "delete", "do", "else", "finally", "for", "function",
695 "if", "in", "instanceof", "new", "return", "switch",
696 "this", "throw", "try", "typeof", "var", "void",
701 "class", "enum", "export", "extends", "import", "super",
703 "abstract", "boolean", "byte", "char", "double", "final",
704 "float", "goto", "int", "long", "native", "short",
705 "synchronized", "throws", "transient", "volatile",
712 const char *CYString::Word() const {
713 if (size_
== 0 || !WordStartRange_
[value_
[0]])
715 for (size_t i(1); i
!= size_
; ++i
)
716 if (!WordEndRange_
[value_
[i
]])
718 const char *value(Value());
719 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
720 if (strcmp(*reserved
, value
) == 0)
725 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
726 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
731 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
738 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
741 out
<< ' ' << *value_
;
745 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
746 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
751 void CYTypeLong::Output(CYOutput
&out
) const {
752 out
<< "long" << specifier_
;
755 void CYTypeShort::Output(CYOutput
&out
) const {
756 out
<< "short" << specifier_
;
759 void CYTypeSigned::Output(CYOutput
&out
) const {
760 out
<< "signed" << specifier_
;
763 void CYTypeUnsigned::Output(CYOutput
&out
) const {
764 out
<< "unsigned" << specifier_
;
767 void CYTypeVariable::Output(CYOutput
&out
) const {
771 void CYTypeVoid::Output(CYOutput
&out
) const {
775 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
777 declarations_
->Output(out
, flags
);
781 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
785 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
786 out
<< "while" << '(' << *test_
<< ')';
787 code_
->Single(out
, CYRight(flags
));
790 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
791 out
<< "with" << '(' << *scope_
<< ')';
792 code_
->Single(out
, CYRight(flags
));
795 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
797 out
<< "objc_getClass(";
798 out
<< '"' << Word() << '"';
803 void CYWord::Output(CYOutput
&out
) const {
805 if (out
.options_
.verbose_
)
806 out
.out_
<< '@' << this;
809 void CYWord::PropertyName(CYOutput
&out
) const {
813 const char *CYWord::Word() const {