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') {
100 if (mode_
== Terminated
&& rhs
!= '}') {
112 } else if (rhs
== '+') {
116 } else if (rhs
== '-') {
117 if (mode_
== NoHyphen
)
120 } else if (WordEndRange_
[rhs
]) {
121 if (mode_
== NoLetter
)
133 CYOutput
&CYOutput::operator <<(const char *rhs
) {
134 size_t size(strlen(rhs
));
137 return *this << *rhs
;
139 if (mode_
== Terminated
)
142 mode_
== NoPlus
&& *rhs
== '+' ||
143 mode_
== NoHyphen
&& *rhs
== '-' ||
144 mode_
== NoLetter
&& WordEndRange_
[*rhs
]
148 if (WordEndRange_
[rhs
[size
- 1]])
158 void CYArgument::Output(CYOutput
&out
) const {
165 value_
->Output(out
, CYPA
, CYNoFlags
);
167 if (next_
->name_
== NULL
)
169 out
<< ' ' << *next_
;
173 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
174 out
<< '[' << elements_
<< ']';
177 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
178 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
181 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
182 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
183 out
<< ' ' << Operator() << ' ';
184 rhs_
->Output(out
, Precedence(), CYRight(flags
));
187 void CYBlock::Output(CYOutput
&out
) const {
190 if (statements_
!= NULL
)
191 statements_
->Multiple(out
);
196 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
197 if (statements_
== NULL
)
199 else if (statements_
->next_
== NULL
)
200 statements_
->Single(out
, flags
);
205 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
206 out
<< (Value() ? "true" : "false");
209 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
212 out
<< ' ' << *label_
;
216 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
217 bool protect((flags
& CYNoCall
) != 0);
220 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
221 out
<< '(' << arguments_
<< ')';
229 void Catch::Output(CYOutput
&out
) const {
230 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ' << code_
;
235 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
242 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
243 if (CYExpression
*expression
= expressions_
)
244 if (CYExpression
*next
= expression
->next_
) {
245 expression
->Output(out
, CYLeft(flags
));
246 CYFlags
center(CYCenter(flags
));
247 while (next
!= NULL
) {
250 next
= expression
->next_
;
251 CYFlags
right(next
!= NULL
? center
: CYRight(flags
));
252 expression
->Output(out
, right
);
255 expression
->Output(out
, flags
);
258 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
259 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
260 out
<< ' ' << '?' << ' ';
262 true_
->Output(out
, CYPA
, CYNoFlags
);
263 out
<< ' ' << ':' << ' ';
264 false_
->Output(out
, CYPA
, CYRight(flags
));
267 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
270 out
<< ' ' << *label_
;
274 void CYClause::Output(CYOutput
&out
) const {
276 out
<< "case" << ' ' << *case_
;
280 if (statements_
!= NULL
)
281 statements_
->Multiple(out
);
285 const char *CYDeclaration::ForEachIn() const {
286 return identifier_
->Word();
289 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
291 Output(out
, CYRight(flags
));
294 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
296 if (initialiser_
!= NULL
) {
297 out
<< ' ' << '=' << ' ';
298 initialiser_
->Output(out
, CYPA
, CYRight(flags
));
302 void CYDeclarations::For(CYOutput
&out
) const {
307 void CYDeclarations::Output(CYOutput
&out
) const {
308 Output(out
, CYNoFlags
);
311 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
312 const CYDeclarations
*declaration(this);
315 CYDeclarations
*next(declaration
->next_
);
316 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
318 declaration
->declaration_
->Output(out
, jacks
);
327 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
328 object_
->Output(out
, Precedence(), CYLeft(flags
));
329 if (const char *word
= property_
->Word())
332 out
<< '[' << *property_
<< ']';
335 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
337 code_
->Single(out
, CYCenter(flags
));
338 out
<< "while" << ' ' << '(' << *test_
<< ')';
341 void CYElement::Output(CYOutput
&out
) const {
343 value_
->Output(out
, CYPA
, CYNoFlags
);
344 if (next_
!= NULL
|| value_
== NULL
) {
346 if (next_
!= NULL
&& next_
->value_
!= NULL
)
353 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
357 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
358 expression_
->Output(out
, flags
| CYNoBF
);
362 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
363 Output(out
, CYPA
, CYNoFlags
);
366 const char *CYExpression::ForEachIn() const {
370 void CYExpression::For(CYOutput
&out
) const {
374 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
375 Output(out
, flags
| CYNoRightHand
);
378 void CYExpression::Output(CYOutput
&out
) const {
379 Output(out
, CYNoFlags
);
382 void CYExpression::Output(CYOutput
&out
, unsigned precedence
, CYFlags flags
) const {
383 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
384 out
<< '(' << *this << ')';
389 void CYFinally::Output(CYOutput
&out
) const {
390 out
<< ' ' << "finally" << ' ' << code_
;
393 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
394 out
<< "for" << ' ' << '(';
395 if (initialiser_
!= NULL
)
396 initialiser_
->For(out
);
402 code_
->Single(out
, CYRight(flags
));
405 void CYForEachIn::Output(CYOutput
&out
, CYFlags flags
) const {
406 out
<< "for" << ' ' << "each" << ' ' << '(';
407 initialiser_
->ForIn(out
, CYNoIn
);
408 out
<< "in" << *set_
<< ')';
409 code_
->Single(out
, CYRight(flags
));
412 void CYForEachInComprehension::Output(CYOutput
&out
) const {
413 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
416 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
417 out
<< "for" << ' ' << '(';
418 if (initialiser_
!= NULL
)
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);
434 if (out
.options_
.verbose_
)
435 out
.out_
<< ':' << static_cast<const CYScope
*>(this);
437 out
<< ' ' << *name_
;
438 out
<< '(' << parameters_
<< ')';
444 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
445 CYFunction::Output(out
, flags
);
448 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
449 CYFunction::Output(out
, flags
);
452 void CYFunctionParameter::Output(CYOutput
&out
) const {
455 out
<< ',' << ' ' << *next_
;
458 const char *CYIdentifier::Word() const {
459 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
462 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
464 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
469 out
<< "if" << ' ' << '(' << *test_
<< ')';
471 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
473 CYFlags
jacks(CYNoDangle
);
477 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
479 true_
->Single(out
, jacks
);
481 if (false_
!= NULL
) {
483 false_
->Single(out
, right
);
490 void CYIfComprehension::Output(CYOutput
&out
) const {
491 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
494 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
495 object_
->Output(out
, Precedence(), CYLeft(flags
));
496 if (const char *word
= property_
->Word())
499 out
<< "->" << '[' << *property_
<< ']';
502 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
503 const char *name(Operator());
504 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
507 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
508 lhs_
->Output(out
, Precedence(), left
);
509 out
<< ' ' << name
<< ' ';
510 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
511 rhs_
->Output(out
, Precedence() - 1, right
);
516 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
517 out
<< *name_
<< ':' << ' ';
518 statement_
->Single(out
, CYRight(flags
));
521 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
522 out
<< "let" << ' ' << '(' << *declarations_
<< ')' << ' ' << code_
;
525 void CYNew::Output(CYOutput
&out
, CYFlags flags
) const {
527 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
528 constructor_
->Output(out
, Precedence(), jacks
);
529 if (arguments_
!= NULL
)
530 out
<< '(' << *arguments_
<< ')';
533 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
537 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
538 std::ostringstream str
;
539 CYNumerify(str
, Value());
540 std::string
value(str
.str());
541 out
<< value
.c_str();
542 // XXX: this should probably also handle hex conversions and exponents
543 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
547 void CYNumber::PropertyName(CYOutput
&out
) const {
548 Output(out
, CYNoFlags
);
551 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
552 bool protect((flags
& CYNoBrace
) != 0);
564 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
565 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
569 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
570 const char *name(Operator());
574 rhs_
->Output(out
, Precedence(), CYRight(flags
));
577 void CYProgram::Output(CYOutput
&out
) const {
578 if (statements_
!= NULL
)
579 statements_
->Multiple(out
);
582 void CYProperty::Output(CYOutput
&out
) const {
584 name_
->PropertyName(out
);
586 value_
->Output(out
, CYPA
, CYNoFlags
);
588 out
<< ',' << '\n' << *next_
;
593 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
597 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
600 out
<< ' ' << *value_
;
604 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
606 for (const CYStatement
*next(this); next
!= NULL
; next
= next
->next_
) {
607 bool last(next
->next_
== NULL
);
608 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYCenter(flags
) : CYRight(flags
));
611 next
->Output(out
, jacks
);
616 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
617 _assert(next_
== NULL
);
626 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
627 std::ostringstream str
;
628 CYStringify(str
, value_
, size_
);
629 out
<< str
.str().c_str();
632 void CYString::PropertyName(CYOutput
&out
) const {
633 if (const char *word
= Word())
639 static const char *Reserved_
[] = {
640 "false", "null", "true",
642 "break", "case", "catch", "continue", "default",
643 "delete", "do", "else", "finally", "for", "function",
644 "if", "in", "instanceof", "new", "return", "switch",
645 "this", "throw", "try", "typeof", "var", "void",
650 "class", "enum", "export", "extends", "import", "super",
652 "abstract", "boolean", "byte", "char", "double", "final",
653 "float", "goto", "int", "long", "native", "short",
654 "synchronized", "throws", "transient", "volatile",
661 const char *CYString::Word() const {
662 if (size_
== 0 || !WordStartRange_
[value_
[0]])
664 for (size_t i(1); i
!= size_
; ++i
)
665 if (!WordEndRange_
[value_
[i
]])
667 const char *value(Value());
668 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
669 if (strcmp(*reserved
, value
) == 0)
674 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
675 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
680 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
687 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
690 out
<< ' ' << *value_
;
694 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
695 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
700 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
702 declarations_
->Output(out
, flags
);
706 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
710 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
711 out
<< "while" << '(' << *test_
<< ')';
712 code_
->Single(out
, CYRight(flags
));
715 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
716 out
<< "with" << '(' << *scope_
<< ')';
717 code_
->Single(out
, CYRight(flags
));
720 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
722 out
<< "objc_getClass(";
723 out
<< '"' << Word() << '"';
728 void CYWord::Output(CYOutput
&out
) const {
730 if (out
.options_
.verbose_
)
731 out
.out_
<< '@' << this;
734 void CYWord::PropertyName(CYOutput
&out
) const {
738 const char *CYWord::Word() const {