]>
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
, unsigned 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 CYTypedIdentifier::Output(CYOutput
&out
) const {
478 // XXX: this is clearly wrong
482 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
483 // XXX: this is seriously wrong
490 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
491 out
<< "typedef" << *typed_
;
494 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
495 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
496 code_
->Single(out
, CYRight(flags
));
502 void New::Output(CYOutput
&out
, CYFlags flags
) const {
504 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
505 constructor_
->Output(out
, Precedence(), jacks
);
506 if (arguments_
!= NULL
)
507 out
<< '(' << *arguments_
<< ')';
512 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
516 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
517 std::ostringstream str
;
518 CYNumerify(str
, Value());
519 std::string
value(str
.str());
520 out
<< value
.c_str();
521 // XXX: this should probably also handle hex conversions and exponents
522 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
526 void CYNumber::PropertyName(CYOutput
&out
) const {
527 Output(out
, CYNoFlags
);
530 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
531 bool protect((flags
& CYNoBrace
) != 0);
543 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
544 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
548 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
549 const char *name(Operator());
553 rhs_
->Output(out
, Precedence(), CYRight(flags
));
556 void CYProgram::Output(CYOutput
&out
) const {
557 if (statements_
!= NULL
)
558 statements_
->Multiple(out
);
561 void CYProperty::Output(CYOutput
&out
) const {
563 name_
->PropertyName(out
);
565 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
567 out
<< ',' << '\n' << *next_
;
572 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
576 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
579 out
<< ' ' << *value_
;
583 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
584 call_
->Output(out
, CYLeft(flags
));
586 proc_
->Output(out
, CYRight(flags
));
589 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
590 // XXX: this is not outputting the parameters
594 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
596 CYForEach (next
, this) {
597 bool last(next
->next_
== NULL
);
598 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
601 next
->Output(out
, jacks
);
606 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
608 return out
.Terminate();
610 _assert(next_
== NULL
);
619 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
620 std::ostringstream str
;
621 CYStringify(str
, value_
, size_
);
622 out
<< str
.str().c_str();
625 void CYString::PropertyName(CYOutput
&out
) const {
626 if (const char *word
= Word())
632 static const char *Reserved_
[] = {
633 "false", "null", "true",
635 "break", "case", "catch", "continue", "default",
636 "delete", "do", "else", "finally", "for", "function",
637 "if", "in", "instanceof", "new", "return", "switch",
638 "this", "throw", "try", "typeof", "var", "void",
643 "class", "enum", "export", "extends", "import", "super",
645 "abstract", "boolean", "byte", "char", "double", "final",
646 "float", "goto", "int", "long", "native", "short",
647 "synchronized", "throws", "transient", "volatile",
654 const char *CYString::Word() const {
655 if (size_
== 0 || !WordStartRange_
[value_
[0]])
657 for (size_t i(1); i
!= size_
; ++i
)
658 if (!WordEndRange_
[value_
[i
]])
660 const char *value(Value());
661 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
662 if (strcmp(*reserved
, value
) == 0)
667 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
668 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
673 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
680 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
683 out
<< ' ' << *value_
;
687 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
688 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
693 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
695 declarations_
->Output(out
, flags
);
699 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
703 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
704 out
<< "while" << '(' << *test_
<< ')';
705 code_
->Single(out
, CYRight(flags
));
708 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
709 out
<< "with" << '(' << *scope_
<< ')';
710 code_
->Single(out
, CYRight(flags
));
713 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
715 out
<< "objc_getClass(";
716 out
<< '"' << Word() << '"';
721 void CYWord::Output(CYOutput
&out
) const {
723 if (out
.options_
.verbose_
)
724 out
.out_
<< '@' << this;
727 void CYWord::PropertyName(CYOutput
&out
) const {
731 const char *CYWord::Word() const {