]>
git.saurik.com Git - cycript.git/blob - Output.cpp
9ffc4f67037e790067db5ce971bd00d503f0eb94
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
)
94 if (mode_
== Terminated
&& rhs
!= '}')
104 } else if (rhs
== '+') {
108 } else if (rhs
== '-') {
109 if (mode_
== NoHyphen
)
112 } else if (WordEndRange_
[rhs
]) {
113 if (mode_
== NoLetter
)
124 CYOutput
&CYOutput::operator <<(const char *rhs
) {
125 size_t size(strlen(rhs
));
128 return *this << *rhs
;
130 if (mode_
== Terminated
)
133 mode_
== NoPlus
&& *rhs
== '+' ||
134 mode_
== NoHyphen
&& *rhs
== '-' ||
135 mode_
== NoLetter
&& WordEndRange_
[*rhs
]
139 if (WordEndRange_
[rhs
[size
- 1]])
148 void CYArgument::Output(CYOutput
&out
) const {
155 value_
->Output(out
, CYPA
, CYNoFlags
);
157 if (next_
->name_
== NULL
)
159 out
<< ' ' << *next_
;
163 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
164 out
<< '[' << elements_
<< ']';
167 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
168 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
171 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
172 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
173 out
<< ' ' << Operator() << ' ';
174 rhs_
->Output(out
, Precedence(), CYRight(flags
));
177 void CYBlock::Output(CYOutput
&out
) const {
180 if (statements_
!= NULL
)
181 statements_
->Multiple(out
);
186 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
187 if (statements_
== NULL
)
189 else if (statements_
->next_
== NULL
)
190 statements_
->Single(out
, flags
);
195 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
196 out
<< (Value() ? "true" : "false");
199 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
202 out
<< ' ' << *label_
;
206 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
207 bool protect((flags
& CYNoCall
) != 0);
210 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
211 out
<< '(' << arguments_
<< ')';
219 void Catch::Output(CYOutput
&out
) const {
220 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ' << code_
;
225 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
226 if (CYExpression
*expression
= expressions_
)
227 if (CYExpression
*next
= expression
->next_
) {
228 expression
->Output(out
, CYLeft(flags
));
229 CYFlags
center(CYCenter(flags
));
230 while (next
!= NULL
) {
233 next
= expression
->next_
;
234 CYFlags
right(next
!= NULL
? center
: CYRight(flags
));
235 expression
->Output(out
, right
);
238 expression
->Output(out
, flags
);
241 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
242 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
243 out
<< ' ' << '?' << ' ';
245 true_
->Output(out
, CYPA
, CYNoFlags
);
246 out
<< ' ' << ':' << ' ';
247 false_
->Output(out
, CYPA
, CYRight(flags
));
250 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
253 out
<< ' ' << *label_
;
257 void CYClause::Output(CYOutput
&out
) const {
259 out
<< "case" << ' ' << *case_
;
263 if (statements_
!= NULL
)
264 statements_
->Multiple(out
);
268 const char *CYDeclaration::ForEachIn() const {
269 return identifier_
->Value();
272 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
274 Output(out
, CYRight(flags
));
277 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
279 if (initialiser_
!= NULL
) {
280 out
<< ' ' << '=' << ' ';
281 initialiser_
->Output(out
, CYPA
, CYRight(flags
));
285 void CYDeclarations::For(CYOutput
&out
) const {
290 void CYDeclarations::Output(CYOutput
&out
) const {
291 Output(out
, CYNoFlags
);
294 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
295 const CYDeclarations
*declaration(this);
298 CYDeclarations
*next(declaration
->next_
);
299 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
301 declaration
->declaration_
->Output(out
, jacks
);
310 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
311 object_
->Output(out
, Precedence(), CYLeft(flags
));
312 if (const char *word
= property_
->Word())
315 out
<< '[' << *property_
<< ']';
318 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
320 code_
->Single(out
, CYCenter(flags
));
321 out
<< "while" << ' ' << '(' << *test_
<< ')';
324 void CYElement::Output(CYOutput
&out
) const {
326 value_
->Output(out
, CYPA
, CYNoFlags
);
327 if (next_
!= NULL
|| value_
== NULL
) {
329 if (next_
!= NULL
&& next_
->value_
!= NULL
)
336 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
340 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
341 expression_
->Output(out
, flags
| CYNoBF
);
345 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
346 Output(out
, CYPA
, CYNoFlags
);
349 const char *CYExpression::ForEachIn() const {
353 void CYExpression::For(CYOutput
&out
) const {
357 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
358 Output(out
, flags
| CYNoRightHand
);
361 void CYExpression::Output(CYOutput
&out
) const {
362 Output(out
, CYNoFlags
);
365 void CYExpression::Output(CYOutput
&out
, unsigned precedence
, CYFlags flags
) const {
366 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
367 out
<< '(' << *this << ')';
372 void CYFinally::Output(CYOutput
&out
) const {
373 out
<< ' ' << "finally" << ' ' << code_
;
376 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
377 out
<< "for" << ' ' << '(';
378 if (initialiser_
!= NULL
)
379 initialiser_
->For(out
);
385 code_
->Single(out
, CYRight(flags
));
388 void CYForEachIn::Output(CYOutput
&out
, CYFlags flags
) const {
389 out
<< "for" << ' ' << "each" << ' ' << '(';
390 initialiser_
->ForIn(out
, CYNoIn
);
391 out
<< "in" << *set_
<< ')';
392 code_
->Single(out
, CYRight(flags
));
395 void CYForEachInComprehension::Output(CYOutput
&out
) const {
396 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
399 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
400 out
<< "for" << ' ' << '(';
401 initialiser_
->ForIn(out
, CYNoIn
);
402 out
<< "in" << *set_
<< ')';
403 code_
->Single(out
, CYRight(flags
));
406 void CYForInComprehension::Output(CYOutput
&out
) const {
407 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
410 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
411 // XXX: one could imagine using + here to save a byte
412 bool protect((flags
& CYNoFunction
) != 0);
417 out
<< ' ' << *name_
;
418 out
<< '(' << parameters_
<< ')';
424 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
425 CYFunction::Output(out
, flags
);
428 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
429 CYFunction::Output(out
, flags
);
432 void CYFunctionParameter::Output(CYOutput
&out
) const {
435 out
<< ',' << ' ' << *next_
;
438 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
440 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
445 out
<< "if" << ' ' << '(' << *test_
<< ')';
447 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
449 CYFlags
jacks(CYNoDangle
);
453 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
455 true_
->Single(out
, jacks
);
457 if (false_
!= NULL
) {
459 false_
->Single(out
, right
);
466 void CYIfComprehension::Output(CYOutput
&out
) const {
467 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
470 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
471 object_
->Output(out
, Precedence(), CYLeft(flags
));
472 if (const char *word
= property_
->Word())
475 out
<< "->" << '[' << *property_
<< ']';
478 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
479 const char *name(Operator());
480 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
483 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
484 lhs_
->Output(out
, Precedence(), left
);
485 out
<< ' ' << name
<< ' ';
486 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
487 rhs_
->Output(out
, Precedence() - 1, right
);
492 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
493 out
<< *name_
<< ':' << ' ';
494 statement_
->Single(out
, CYRight(flags
));
497 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
498 out
<< "let" << ' ' << '(' << *declarations_
<< ')' << ' ' << code_
;
501 void CYNew::Output(CYOutput
&out
, CYFlags flags
) const {
503 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
504 constructor_
->Output(out
, Precedence(), jacks
);
505 if (arguments_
!= NULL
)
506 out
<< '(' << *arguments_
<< ')';
509 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
513 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
514 std::ostringstream str
;
515 CYNumerify(str
, Value());
516 std::string
value(str
.str());
517 out
<< value
.c_str();
518 // XXX: this should probably also handle hex conversions and exponents
519 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
523 void CYNumber::PropertyName(CYOutput
&out
) const {
524 Output(out
, CYNoFlags
);
527 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
528 bool protect((flags
& CYNoBrace
) != 0);
540 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
541 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
545 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
546 const char *name(Operator());
550 rhs_
->Output(out
, Precedence(), CYRight(flags
));
553 void CYProgram::Output(CYOutput
&out
) const {
554 if (statements_
!= NULL
)
555 statements_
->Multiple(out
);
558 void CYProperty::Output(CYOutput
&out
) const {
560 name_
->PropertyName(out
);
562 value_
->Output(out
, CYPA
, CYNoFlags
);
564 out
<< ',' << '\n' << *next_
;
569 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
573 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
576 out
<< ' ' << *value_
;
580 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
582 for (const CYStatement
*next(this); next
!= NULL
; next
= next
->next_
) {
583 bool last(next
->next_
== NULL
);
584 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYCenter(flags
) : CYRight(flags
));
587 next
->Output(out
, jacks
);
592 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
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",
639 const char *CYString::Word() const {
640 if (size_
== 0 || !WordStartRange_
[value_
[0]])
642 for (size_t i(1); i
!= size_
; ++i
)
643 if (!WordEndRange_
[value_
[i
]])
645 const char *value(Value());
646 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
647 if (strcmp(*reserved
, value
) == 0)
652 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
653 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
658 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
665 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
668 out
<< ' ' << *value_
;
672 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
673 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
678 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
680 declarations_
->Output(out
, flags
);
684 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
688 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
689 out
<< "while" << '(' << *test_
<< ')';
690 code_
->Single(out
, CYRight(flags
));
693 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
694 out
<< "with" << '(' << *scope_
<< ')';
695 code_
->Single(out
, CYRight(flags
));
698 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
700 out
<< "objc_getClass(";
701 out
<< '"' << Value() << '"';
706 void CYWord::Output(CYOutput
&out
) const {
710 void CYWord::PropertyName(CYOutput
&out
) const {