]>
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 CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
478 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
479 code_
->Single(out
, CYRight(flags
));
485 void New::Output(CYOutput
&out
, CYFlags flags
) const {
487 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
488 constructor_
->Output(out
, Precedence(), jacks
);
489 if (arguments_
!= NULL
)
490 out
<< '(' << *arguments_
<< ')';
495 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
499 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
500 std::ostringstream str
;
501 CYNumerify(str
, Value());
502 std::string
value(str
.str());
503 out
<< value
.c_str();
504 // XXX: this should probably also handle hex conversions and exponents
505 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
509 void CYNumber::PropertyName(CYOutput
&out
) const {
510 Output(out
, CYNoFlags
);
513 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
514 bool protect((flags
& CYNoBrace
) != 0);
526 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
527 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
531 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
532 const char *name(Operator());
536 rhs_
->Output(out
, Precedence(), CYRight(flags
));
539 void CYProgram::Output(CYOutput
&out
) const {
540 if (statements_
!= NULL
)
541 statements_
->Multiple(out
);
544 void CYProperty::Output(CYOutput
&out
) const {
546 name_
->PropertyName(out
);
548 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
550 out
<< ',' << '\n' << *next_
;
555 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
559 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
562 out
<< ' ' << *value_
;
566 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
567 call_
->Output(out
, CYLeft(flags
));
569 proc_
->Output(out
, CYRight(flags
));
572 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
573 // XXX: this is not outputting the parameters
577 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
579 CYForEach (next
, this) {
580 bool last(next
->next_
== NULL
);
581 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
584 next
->Output(out
, jacks
);
589 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
591 return out
.Terminate();
593 _assert(next_
== NULL
);
602 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
603 std::ostringstream str
;
604 CYStringify(str
, value_
, size_
);
605 out
<< str
.str().c_str();
608 void CYString::PropertyName(CYOutput
&out
) const {
609 if (const char *word
= Word())
615 static const char *Reserved_
[] = {
616 "false", "null", "true",
618 "break", "case", "catch", "continue", "default",
619 "delete", "do", "else", "finally", "for", "function",
620 "if", "in", "instanceof", "new", "return", "switch",
621 "this", "throw", "try", "typeof", "var", "void",
626 "class", "enum", "export", "extends", "import", "super",
628 "abstract", "boolean", "byte", "char", "double", "final",
629 "float", "goto", "int", "long", "native", "short",
630 "synchronized", "throws", "transient", "volatile",
637 const char *CYString::Word() const {
638 if (size_
== 0 || !WordStartRange_
[value_
[0]])
640 for (size_t i(1); i
!= size_
; ++i
)
641 if (!WordEndRange_
[value_
[i
]])
643 const char *value(Value());
644 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
645 if (strcmp(*reserved
, value
) == 0)
650 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
651 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
656 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
663 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
666 out
<< ' ' << *value_
;
670 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
671 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
676 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
678 declarations_
->Output(out
, flags
);
682 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
686 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
687 out
<< "while" << '(' << *test_
<< ')';
688 code_
->Single(out
, CYRight(flags
));
691 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
692 out
<< "with" << '(' << *scope_
<< ')';
693 code_
->Single(out
, CYRight(flags
));
696 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
698 out
<< "objc_getClass(";
699 out
<< '"' << Word() << '"';
704 void CYWord::Output(CYOutput
&out
) const {
706 if (out
.options_
.verbose_
)
707 out
.out_
<< '@' << this;
710 void CYWord::PropertyName(CYOutput
&out
) const {
714 const char *CYWord::Word() const {