]>
git.saurik.com Git - cycript.git/blob - Output.cpp
04f893c9299d74671fb812a04a1975ed40ee2980
1 /* Cycript - Inlining/Optimizing JavaScript Compiler
2 * Copyright (C) 2009 Jay Freeman (saurik)
5 /* Modified BSD License {{{ */
7 * Redistribution and use in source and binary
8 * forms, with or without modification, are permitted
9 * provided that the following conditions are met:
11 * 1. Redistributions of source code must retain the
12 * above copyright notice, this list of conditions
13 * and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the
15 * above copyright notice, this list of conditions
16 * and the following disclaimer in the documentation
17 * and/or other materials provided with the
19 * 3. The name of the author may not be used to endorse
20 * or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
25 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include "cycript.hpp"
45 _finline CYFlags
operator ~(CYFlags rhs
) {
46 return static_cast<CYFlags
>(~static_cast<unsigned>(rhs
));
49 _finline CYFlags
operator &(CYFlags lhs
, CYFlags rhs
) {
50 return static_cast<CYFlags
>(static_cast<unsigned>(lhs
) & static_cast<unsigned>(rhs
));
53 _finline CYFlags
operator |(CYFlags lhs
, CYFlags rhs
) {
54 return static_cast<CYFlags
>(static_cast<unsigned>(lhs
) | static_cast<unsigned>(rhs
));
57 _finline CYFlags
&operator |=(CYFlags
&lhs
, CYFlags rhs
) {
58 return lhs
= lhs
| rhs
;
61 _finline CYFlags
CYLeft(CYFlags flags
) {
62 return flags
& ~(CYNoDangle
| CYNoInteger
);
65 _finline CYFlags
CYRight(CYFlags flags
) {
66 return flags
& ~CYNoBF
;
69 _finline CYFlags
CYCenter(CYFlags flags
) {
70 return CYLeft(CYRight(flags
));
73 void CYOutput::Terminate() {
78 CYOutput
&CYOutput::operator <<(char rhs
) {
79 if (rhs
== ' ' || rhs
== '\n')
85 for (unsigned i(0); i
!= indent_
; ++i
)
88 else if (rhs
== '\r') {
102 if (mode_
== Terminated
&& rhs
!= '}') {
114 } else if (rhs
== '+') {
118 } else if (rhs
== '-') {
119 if (mode_
== NoHyphen
)
122 } else if (WordEndRange_
[rhs
]) {
123 if (mode_
== NoLetter
)
135 CYOutput
&CYOutput::operator <<(const char *rhs
) {
136 size_t size(strlen(rhs
));
139 return *this << *rhs
;
141 if (mode_
== Terminated
)
144 mode_
== NoPlus
&& *rhs
== '+' ||
145 mode_
== NoHyphen
&& *rhs
== '-' ||
146 mode_
== NoLetter
&& WordEndRange_
[*rhs
]
150 if (WordEndRange_
[rhs
[size
- 1]])
160 void CYArgument::Output(CYOutput
&out
) const {
167 value_
->Output(out
, CYPA
, CYNoFlags
);
169 if (next_
->name_
== NULL
)
171 out
<< ' ' << *next_
;
175 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
176 out
<< '[' << elements_
<< ']';
179 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
180 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
183 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
184 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
185 out
<< ' ' << Operator() << ' ';
186 rhs_
->Output(out
, Precedence(), CYRight(flags
));
189 void CYBlock::Output(CYOutput
&out
) const {
192 if (statements_
!= NULL
)
193 statements_
->Multiple(out
);
198 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
199 if (statements_
== NULL
)
201 else if (statements_
->next_
== NULL
)
202 statements_
->Single(out
, flags
);
207 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
208 out
<< (Value() ? "true" : "false");
211 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
214 out
<< ' ' << *label_
;
218 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
219 bool protect((flags
& CYNoCall
) != 0);
222 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
223 out
<< '(' << arguments_
<< ')';
231 void Catch::Output(CYOutput
&out
) const {
232 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ' << code_
;
237 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
243 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
244 if (CYExpression
*expression
= expressions_
)
245 if (CYExpression
*next
= expression
->next_
) {
246 expression
->Output(out
, CYLeft(flags
));
247 CYFlags
center(CYCenter(flags
));
248 while (next
!= NULL
) {
251 next
= expression
->next_
;
252 CYFlags
right(next
!= NULL
? center
: CYRight(flags
));
253 expression
->Output(out
, right
);
256 expression
->Output(out
, flags
);
259 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
260 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
261 out
<< ' ' << '?' << ' ';
263 true_
->Output(out
, CYPA
, CYNoFlags
);
264 out
<< ' ' << ':' << ' ';
265 false_
->Output(out
, CYPA
, CYRight(flags
));
268 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
271 out
<< ' ' << *label_
;
275 void CYClause::Output(CYOutput
&out
) const {
277 out
<< "case" << ' ' << *case_
;
281 if (statements_
!= NULL
)
282 statements_
->Multiple(out
);
286 const char *CYDeclaration::ForEachIn() const {
287 return identifier_
->Value();
290 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
292 Output(out
, CYRight(flags
));
295 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
297 if (initialiser_
!= NULL
) {
298 out
<< ' ' << '=' << ' ';
299 initialiser_
->Output(out
, CYPA
, CYRight(flags
));
303 void CYDeclarations::For(CYOutput
&out
) const {
308 void CYDeclarations::Output(CYOutput
&out
) const {
309 Output(out
, CYNoFlags
);
312 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
313 const CYDeclarations
*declaration(this);
316 CYDeclarations
*next(declaration
->next_
);
317 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
319 declaration
->declaration_
->Output(out
, jacks
);
328 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
329 object_
->Output(out
, Precedence(), CYLeft(flags
));
330 if (const char *word
= property_
->Word())
333 out
<< '[' << *property_
<< ']';
336 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
338 code_
->Single(out
, CYCenter(flags
));
339 out
<< "while" << ' ' << '(' << *test_
<< ')';
342 void CYElement::Output(CYOutput
&out
) const {
344 value_
->Output(out
, CYPA
, CYNoFlags
);
345 if (next_
!= NULL
|| value_
== NULL
) {
347 if (next_
!= NULL
&& next_
->value_
!= NULL
)
354 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
358 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
359 expression_
->Output(out
, flags
| CYNoBF
);
363 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
364 Output(out
, CYPA
, CYNoFlags
);
367 const char *CYExpression::ForEachIn() const {
371 void CYExpression::For(CYOutput
&out
) const {
375 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
376 Output(out
, flags
| CYNoRightHand
);
379 void CYExpression::Output(CYOutput
&out
) const {
380 Output(out
, CYNoFlags
);
383 void CYExpression::Output(CYOutput
&out
, unsigned precedence
, CYFlags flags
) const {
384 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
385 out
<< '(' << *this << ')';
390 void CYFinally::Output(CYOutput
&out
) const {
391 out
<< ' ' << "finally" << ' ' << code_
;
394 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
395 out
<< "for" << ' ' << '(';
396 if (initialiser_
!= NULL
)
397 initialiser_
->For(out
);
403 code_
->Single(out
, CYRight(flags
));
406 void CYForEachIn::Output(CYOutput
&out
, CYFlags flags
) const {
407 out
<< "for" << ' ' << "each" << ' ' << '(';
408 initialiser_
->ForIn(out
, CYNoIn
);
409 out
<< "in" << *set_
<< ')';
410 code_
->Single(out
, CYRight(flags
));
413 void CYForEachInComprehension::Output(CYOutput
&out
) const {
414 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
417 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
418 out
<< "for" << ' ' << '(';
419 initialiser_
->ForIn(out
, CYNoIn
);
420 out
<< "in" << *set_
<< ')';
421 code_
->Single(out
, CYRight(flags
));
424 void CYForInComprehension::Output(CYOutput
&out
) const {
425 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
428 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
429 // XXX: one could imagine using + here to save a byte
430 bool protect((flags
& CYNoFunction
) != 0);
435 out
<< ' ' << *name_
;
436 out
<< '(' << parameters_
<< ')';
442 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
443 CYFunction::Output(out
, flags
);
446 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
447 CYFunction::Output(out
, flags
);
450 void CYFunctionParameter::Output(CYOutput
&out
) const {
453 out
<< ',' << ' ' << *next_
;
456 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
458 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
463 out
<< "if" << ' ' << '(' << *test_
<< ')';
465 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
467 CYFlags
jacks(CYNoDangle
);
471 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
473 true_
->Single(out
, jacks
);
475 if (false_
!= NULL
) {
477 false_
->Single(out
, right
);
484 void CYIfComprehension::Output(CYOutput
&out
) const {
485 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
488 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
489 object_
->Output(out
, Precedence(), CYLeft(flags
));
490 if (const char *word
= property_
->Word())
493 out
<< "->" << '[' << *property_
<< ']';
496 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
497 const char *name(Operator());
498 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
501 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
502 lhs_
->Output(out
, Precedence(), left
);
503 out
<< ' ' << name
<< ' ';
504 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
505 rhs_
->Output(out
, Precedence() - 1, right
);
510 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
511 out
<< *name_
<< ':' << ' ';
512 statement_
->Single(out
, CYRight(flags
));
515 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
516 out
<< "let" << ' ' << '(' << *declarations_
<< ')' << ' ' << code_
;
519 void CYNew::Output(CYOutput
&out
, CYFlags flags
) const {
521 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
522 constructor_
->Output(out
, Precedence(), jacks
);
523 if (arguments_
!= NULL
)
524 out
<< '(' << *arguments_
<< ')';
527 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
531 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
532 std::ostringstream str
;
533 CYNumerify(str
, Value());
534 std::string
value(str
.str());
535 out
<< value
.c_str();
536 // XXX: this should probably also handle hex conversions and exponents
537 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
541 void CYNumber::PropertyName(CYOutput
&out
) const {
542 Output(out
, CYNoFlags
);
545 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
546 bool protect((flags
& CYNoBrace
) != 0);
558 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
559 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
563 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
564 const char *name(Operator());
568 rhs_
->Output(out
, Precedence(), CYRight(flags
));
571 void CYProgram::Output(CYOutput
&out
) const {
572 if (statements_
!= NULL
)
573 statements_
->Multiple(out
);
576 void CYProperty::Output(CYOutput
&out
) const {
578 name_
->PropertyName(out
);
580 value_
->Output(out
, CYPA
, CYNoFlags
);
582 out
<< ',' << '\n' << *next_
;
587 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
591 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
594 out
<< ' ' << *value_
;
598 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
600 for (const CYStatement
*next(this); next
!= NULL
; next
= next
->next_
) {
601 bool last(next
->next_
== NULL
);
602 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYCenter(flags
) : CYRight(flags
));
605 next
->Output(out
, jacks
);
610 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
611 _assert(next_
== NULL
);
620 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
621 std::ostringstream str
;
622 CYStringify(str
, value_
, size_
);
623 out
<< str
.str().c_str();
626 void CYString::PropertyName(CYOutput
&out
) const {
627 if (const char *word
= Word())
633 static const char *Reserved_
[] = {
634 "false", "null", "true",
636 "break", "case", "catch", "continue", "default",
637 "delete", "do", "else", "finally", "for", "function",
638 "if", "in", "instanceof", "new", "return", "switch",
639 "this", "throw", "try", "typeof", "var", "void",
644 "class", "enum", "export", "extends", "import", "super",
646 "abstract", "boolean", "byte", "char", "double", "final",
647 "float", "goto", "int", "long", "native", "short",
648 "synchronized", "throws", "transient", "volatile",
657 const char *CYString::Word() const {
658 if (size_
== 0 || !WordStartRange_
[value_
[0]])
660 for (size_t i(1); i
!= size_
; ++i
)
661 if (!WordEndRange_
[value_
[i
]])
663 const char *value(Value());
664 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
665 if (strcmp(*reserved
, value
) == 0)
670 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
671 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
676 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
683 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
686 out
<< ' ' << *value_
;
690 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
691 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
696 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
698 declarations_
->Output(out
, flags
);
702 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
706 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
707 out
<< "while" << '(' << *test_
<< ')';
708 code_
->Single(out
, CYRight(flags
));
711 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
712 out
<< "with" << '(' << *scope_
<< ')';
713 code_
->Single(out
, CYRight(flags
));
716 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
718 out
<< "objc_getClass(";
719 out
<< '"' << Value() << '"';
724 void CYWord::Output(CYOutput
&out
) const {
728 void CYWord::PropertyName(CYOutput
&out
) const {