]>
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') {
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 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
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
) | CYNoInteger
);
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 if (initialiser_
!= NULL
)
420 initialiser_
->ForIn(out
, CYNoIn
);
421 out
<< "in" << *set_
<< ')';
422 code_
->Single(out
, CYRight(flags
));
425 void CYForInComprehension::Output(CYOutput
&out
) const {
426 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
429 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
430 // XXX: one could imagine using + here to save a byte
431 bool protect((flags
& CYNoFunction
) != 0);
436 out
<< ' ' << *name_
;
437 out
<< '(' << parameters_
<< ')';
443 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
444 CYFunction::Output(out
, flags
);
447 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
448 CYFunction::Output(out
, flags
);
451 void CYFunctionParameter::Output(CYOutput
&out
) const {
454 out
<< ',' << ' ' << *next_
;
457 const char *CYIdentifier::Word() const {
458 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
461 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
463 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
468 out
<< "if" << ' ' << '(' << *test_
<< ')';
470 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
472 CYFlags
jacks(CYNoDangle
);
476 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
478 true_
->Single(out
, jacks
);
480 if (false_
!= NULL
) {
482 false_
->Single(out
, right
);
489 void CYIfComprehension::Output(CYOutput
&out
) const {
490 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
493 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
494 object_
->Output(out
, Precedence(), CYLeft(flags
));
495 if (const char *word
= property_
->Word())
498 out
<< "->" << '[' << *property_
<< ']';
501 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
502 const char *name(Operator());
503 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
506 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
507 lhs_
->Output(out
, Precedence(), left
);
508 out
<< ' ' << name
<< ' ';
509 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
510 rhs_
->Output(out
, Precedence() - 1, right
);
515 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
516 out
<< *name_
<< ':' << ' ';
517 statement_
->Single(out
, CYRight(flags
));
520 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
521 out
<< "let" << ' ' << '(' << *declarations_
<< ')' << ' ' << code_
;
524 void CYNew::Output(CYOutput
&out
, CYFlags flags
) const {
526 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
527 constructor_
->Output(out
, Precedence(), jacks
);
528 if (arguments_
!= NULL
)
529 out
<< '(' << *arguments_
<< ')';
532 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
536 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
537 std::ostringstream str
;
538 CYNumerify(str
, Value());
539 std::string
value(str
.str());
540 out
<< value
.c_str();
541 // XXX: this should probably also handle hex conversions and exponents
542 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
546 void CYNumber::PropertyName(CYOutput
&out
) const {
547 Output(out
, CYNoFlags
);
550 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
551 bool protect((flags
& CYNoBrace
) != 0);
563 void CYOptionalFunctionParameter::Output(CYOutput
&out
) const {
564 out
<< *name_
<< '=';
565 initializer_
->Output(out
, CYPA
, CYNoFlags
);
567 out
<< ',' << ' ' << *next_
;
570 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
571 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
575 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
576 const char *name(Operator());
580 rhs_
->Output(out
, Precedence(), CYRight(flags
));
583 void CYProgram::Output(CYOutput
&out
) const {
584 if (statements_
!= NULL
)
585 statements_
->Multiple(out
);
588 void CYProperty::Output(CYOutput
&out
) const {
590 name_
->PropertyName(out
);
592 value_
->Output(out
, CYPA
, CYNoFlags
);
594 out
<< ',' << '\n' << *next_
;
599 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
603 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
606 out
<< ' ' << *value_
;
610 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
611 call_
->Output(out
, CYLeft(flags
));
613 proc_
->Output(out
, CYRight(flags
));
616 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
617 // XXX: this is not outputting the parameters
621 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
623 for (const CYStatement
*next(this); next
!= NULL
; next
= next
->next_
) {
624 bool last(next
->next_
== NULL
);
625 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYCenter(flags
) : CYRight(flags
));
628 next
->Output(out
, jacks
);
633 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
634 _assert(next_
== NULL
);
643 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
644 std::ostringstream str
;
645 CYStringify(str
, value_
, size_
);
646 out
<< str
.str().c_str();
649 void CYString::PropertyName(CYOutput
&out
) const {
650 if (const char *word
= Word())
656 static const char *Reserved_
[] = {
657 "false", "null", "true",
659 "break", "case", "catch", "continue", "default",
660 "delete", "do", "else", "finally", "for", "function",
661 "if", "in", "instanceof", "new", "return", "switch",
662 "this", "throw", "try", "typeof", "var", "void",
667 "class", "enum", "export", "extends", "import", "super",
669 "abstract", "boolean", "byte", "char", "double", "final",
670 "float", "goto", "int", "long", "native", "short",
671 "synchronized", "throws", "transient", "volatile",
678 const char *CYString::Word() const {
679 if (size_
== 0 || !WordStartRange_
[value_
[0]])
681 for (size_t i(1); i
!= size_
; ++i
)
682 if (!WordEndRange_
[value_
[i
]])
684 const char *value(Value());
685 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
686 if (strcmp(*reserved
, value
) == 0)
691 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
692 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
697 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
704 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
707 out
<< ' ' << *value_
;
711 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
712 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
717 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
719 declarations_
->Output(out
, flags
);
723 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
727 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
728 out
<< "while" << '(' << *test_
<< ')';
729 code_
->Single(out
, CYRight(flags
));
732 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
733 out
<< "with" << '(' << *scope_
<< ')';
734 code_
->Single(out
, CYRight(flags
));
737 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
739 out
<< "objc_getClass(";
740 out
<< '"' << Word() << '"';
745 void CYWord::Output(CYOutput
&out
) const {
747 if (out
.options_
.verbose_
)
748 out
.out_
<< '@' << this;
751 void CYWord::PropertyName(CYOutput
&out
) const {
755 const char *CYWord::Word() const {