]>
git.saurik.com Git - cycript.git/blob - Output.cpp
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_
->Word();
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 {
359 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
360 expression_
->Output(out
, flags
| CYNoBF
);
364 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
365 Output(out
, CYPA
, CYNoFlags
);
368 const char *CYExpression::ForEachIn() const {
372 void CYExpression::For(CYOutput
&out
) const {
376 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
377 Output(out
, flags
| CYNoRightHand
);
380 void CYExpression::Output(CYOutput
&out
) const {
381 Output(out
, CYNoFlags
);
384 void CYExpression::Output(CYOutput
&out
, unsigned precedence
, CYFlags flags
) const {
385 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
386 out
<< '(' << *this << ')';
391 void CYFinally::Output(CYOutput
&out
) const {
392 out
<< ' ' << "finally" << ' ' << code_
;
395 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
396 out
<< "for" << ' ' << '(';
397 if (initialiser_
!= NULL
)
398 initialiser_
->For(out
);
404 code_
->Single(out
, CYRight(flags
));
407 void CYForEachIn::Output(CYOutput
&out
, CYFlags flags
) const {
408 out
<< "for" << ' ' << "each" << ' ' << '(';
409 initialiser_
->ForIn(out
, CYNoIn
);
410 out
<< "in" << *set_
<< ')';
411 code_
->Single(out
, CYRight(flags
));
414 void CYForEachInComprehension::Output(CYOutput
&out
) const {
415 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
418 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
419 out
<< "for" << ' ' << '(';
420 if (initialiser_
!= NULL
)
421 initialiser_
->ForIn(out
, CYNoIn
);
422 out
<< "in" << *set_
<< ')';
423 code_
->Single(out
, CYRight(flags
));
426 void CYForInComprehension::Output(CYOutput
&out
) const {
427 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
430 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
431 // XXX: one could imagine using + here to save a byte
432 bool protect((flags
& CYNoFunction
) != 0);
436 if (out
.options_
.verbose_
)
437 out
.out_
<< ':' << static_cast<const CYScope
*>(this);
439 out
<< ' ' << *name_
;
440 out
<< '(' << parameters_
<< ')';
446 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
447 CYFunction::Output(out
, flags
);
450 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
451 CYFunction::Output(out
, flags
);
454 void CYFunctionParameter::Output(CYOutput
&out
) const {
457 out
<< ',' << ' ' << *next_
;
460 const char *CYIdentifier::Word() const {
461 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
464 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
466 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
471 out
<< "if" << ' ' << '(' << *test_
<< ')';
473 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
475 CYFlags
jacks(CYNoDangle
);
479 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
481 true_
->Single(out
, jacks
);
483 if (false_
!= NULL
) {
485 false_
->Single(out
, right
);
492 void CYIfComprehension::Output(CYOutput
&out
) const {
493 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
496 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
497 object_
->Output(out
, Precedence(), CYLeft(flags
));
498 if (const char *word
= property_
->Word())
501 out
<< "->" << '[' << *property_
<< ']';
504 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
505 const char *name(Operator());
506 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
509 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
510 lhs_
->Output(out
, Precedence(), left
);
511 out
<< ' ' << name
<< ' ';
512 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
513 rhs_
->Output(out
, Precedence() - 1, right
);
518 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
519 out
<< *name_
<< ':' << ' ';
520 statement_
->Single(out
, CYRight(flags
));
523 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
524 out
<< "let" << ' ' << '(' << *declarations_
<< ')' << ' ' << code_
;
527 void CYNew::Output(CYOutput
&out
, CYFlags flags
) const {
529 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
530 constructor_
->Output(out
, Precedence(), jacks
);
531 if (arguments_
!= NULL
)
532 out
<< '(' << *arguments_
<< ')';
535 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
539 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
540 std::ostringstream str
;
541 CYNumerify(str
, Value());
542 std::string
value(str
.str());
543 out
<< value
.c_str();
544 // XXX: this should probably also handle hex conversions and exponents
545 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
549 void CYNumber::PropertyName(CYOutput
&out
) const {
550 Output(out
, CYNoFlags
);
553 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
554 bool protect((flags
& CYNoBrace
) != 0);
566 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
567 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
571 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
572 const char *name(Operator());
576 rhs_
->Output(out
, Precedence(), CYRight(flags
));
579 void CYProgram::Output(CYOutput
&out
) const {
580 if (statements_
!= NULL
)
581 statements_
->Multiple(out
);
584 void CYProperty::Output(CYOutput
&out
) const {
586 name_
->PropertyName(out
);
588 value_
->Output(out
, CYPA
, CYNoFlags
);
590 out
<< ',' << '\n' << *next_
;
595 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
599 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
602 out
<< ' ' << *value_
;
606 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
608 for (const CYStatement
*next(this); next
!= NULL
; next
= next
->next_
) {
609 bool last(next
->next_
== NULL
);
610 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYCenter(flags
) : CYRight(flags
));
613 next
->Output(out
, jacks
);
618 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
619 _assert(next_
== NULL
);
628 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
629 std::ostringstream str
;
630 CYStringify(str
, value_
, size_
);
631 out
<< str
.str().c_str();
634 void CYString::PropertyName(CYOutput
&out
) const {
635 if (const char *word
= Word())
641 static const char *Reserved_
[] = {
642 "false", "null", "true",
644 "break", "case", "catch", "continue", "default",
645 "delete", "do", "else", "finally", "for", "function",
646 "if", "in", "instanceof", "new", "return", "switch",
647 "this", "throw", "try", "typeof", "var", "void",
652 "class", "enum", "export", "extends", "import", "super",
654 "abstract", "boolean", "byte", "char", "double", "final",
655 "float", "goto", "int", "long", "native", "short",
656 "synchronized", "throws", "transient", "volatile",
665 const char *CYString::Word() const {
666 if (size_
== 0 || !WordStartRange_
[value_
[0]])
668 for (size_t i(1); i
!= size_
; ++i
)
669 if (!WordEndRange_
[value_
[i
]])
671 const char *value(Value());
672 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
673 if (strcmp(*reserved
, value
) == 0)
678 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
679 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
684 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
691 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
694 out
<< ' ' << *value_
;
698 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
699 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
704 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
706 declarations_
->Output(out
, flags
);
710 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
714 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
715 out
<< "while" << '(' << *test_
<< ')';
716 code_
->Single(out
, CYRight(flags
));
719 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
720 out
<< "with" << '(' << *scope_
<< ')';
721 code_
->Single(out
, CYRight(flags
));
724 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
726 out
<< "objc_getClass(";
727 out
<< '"' << Word() << '"';
732 void CYWord::Output(CYOutput
&out
) const {
734 if (out
.options_
.verbose_
)
735 out
.out_
<< '@' << this;
738 void CYWord::PropertyName(CYOutput
&out
) const {
742 const char *CYWord::Word() const {