]>
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 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 type_
->Output(out
, 0, CYNoFlags
);
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 CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
747 declarations_
->Output(out
, flags
);
751 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
755 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
756 out
<< "while" << '(' << *test_
<< ')';
757 code_
->Single(out
, CYRight(flags
));
760 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
761 out
<< "with" << '(' << *scope_
<< ')';
762 code_
->Single(out
, CYRight(flags
));
765 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
767 out
<< "objc_getClass(";
768 out
<< '"' << Word() << '"';
773 void CYWord::Output(CYOutput
&out
) const {
775 if (out
.options_
.verbose_
)
776 out
.out_
<< '@' << this;
779 void CYWord::PropertyName(CYOutput
&out
) const {
783 const char *CYWord::Word() const {