]>
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 CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
478 // XXX: this is seriously wrong
485 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
486 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
487 code_
->Single(out
, CYRight(flags
));
493 void New::Output(CYOutput
&out
, CYFlags flags
) const {
495 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
496 constructor_
->Output(out
, Precedence(), jacks
);
497 if (arguments_
!= NULL
)
498 out
<< '(' << *arguments_
<< ')';
503 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
507 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
508 std::ostringstream str
;
509 CYNumerify(str
, Value());
510 std::string
value(str
.str());
511 out
<< value
.c_str();
512 // XXX: this should probably also handle hex conversions and exponents
513 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
517 void CYNumber::PropertyName(CYOutput
&out
) const {
518 Output(out
, CYNoFlags
);
521 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
522 bool protect((flags
& CYNoBrace
) != 0);
534 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
535 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
539 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
540 const char *name(Operator());
544 rhs_
->Output(out
, Precedence(), CYRight(flags
));
547 void CYProgram::Output(CYOutput
&out
) const {
548 if (statements_
!= NULL
)
549 statements_
->Multiple(out
);
552 void CYProperty::Output(CYOutput
&out
) const {
554 name_
->PropertyName(out
);
556 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
558 out
<< ',' << '\n' << *next_
;
563 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
567 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
570 out
<< ' ' << *value_
;
574 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
575 call_
->Output(out
, CYLeft(flags
));
577 proc_
->Output(out
, CYRight(flags
));
580 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
581 // XXX: this is not outputting the parameters
585 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
587 CYForEach (next
, this) {
588 bool last(next
->next_
== NULL
);
589 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
592 next
->Output(out
, jacks
);
597 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
599 return out
.Terminate();
601 _assert(next_
== NULL
);
610 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
611 std::ostringstream str
;
612 CYStringify(str
, value_
, size_
);
613 out
<< str
.str().c_str();
616 void CYString::PropertyName(CYOutput
&out
) const {
617 if (const char *word
= Word())
623 static const char *Reserved_
[] = {
624 "false", "null", "true",
626 "break", "case", "catch", "continue", "default",
627 "delete", "do", "else", "finally", "for", "function",
628 "if", "in", "instanceof", "new", "return", "switch",
629 "this", "throw", "try", "typeof", "var", "void",
634 "class", "enum", "export", "extends", "import", "super",
636 "abstract", "boolean", "byte", "char", "double", "final",
637 "float", "goto", "int", "long", "native", "short",
638 "synchronized", "throws", "transient", "volatile",
645 const char *CYString::Word() const {
646 if (size_
== 0 || !WordStartRange_
[value_
[0]])
648 for (size_t i(1); i
!= size_
; ++i
)
649 if (!WordEndRange_
[value_
[i
]])
651 const char *value(Value());
652 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
653 if (strcmp(*reserved
, value
) == 0)
658 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
659 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
664 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
671 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
674 out
<< ' ' << *value_
;
678 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
679 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
684 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
686 declarations_
->Output(out
, flags
);
690 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
694 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
695 out
<< "while" << '(' << *test_
<< ')';
696 code_
->Single(out
, CYRight(flags
));
699 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
700 out
<< "with" << '(' << *scope_
<< ')';
701 code_
->Single(out
, CYRight(flags
));
704 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
706 out
<< "objc_getClass(";
707 out
<< '"' << Word() << '"';
712 void CYWord::Output(CYOutput
&out
) const {
714 if (out
.options_
.verbose_
)
715 out
.out_
<< '@' << this;
718 void CYWord::PropertyName(CYOutput
&out
) const {
722 const char *CYWord::Word() const {