]>
git.saurik.com Git - cycript.git/blob - Output.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2010 Jay Freeman (saurik)
5 /* GNU Lesser General Public License, Version 3 {{{ */
7 * Cycript is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
12 * Cycript is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
22 #include "cycript.hpp"
27 _finline CYFlags
operator ~(CYFlags rhs
) {
28 return static_cast<CYFlags
>(~static_cast<unsigned>(rhs
));
31 _finline CYFlags
operator &(CYFlags lhs
, CYFlags rhs
) {
32 return static_cast<CYFlags
>(static_cast<unsigned>(lhs
) & static_cast<unsigned>(rhs
));
35 _finline CYFlags
operator |(CYFlags lhs
, CYFlags rhs
) {
36 return static_cast<CYFlags
>(static_cast<unsigned>(lhs
) | static_cast<unsigned>(rhs
));
39 _finline CYFlags
&operator |=(CYFlags
&lhs
, CYFlags rhs
) {
40 return lhs
= lhs
| rhs
;
43 _finline CYFlags
CYLeft(CYFlags flags
) {
44 return flags
& ~(CYNoDangle
| CYNoInteger
);
47 _finline CYFlags
CYRight(CYFlags flags
) {
48 return flags
& ~CYNoBF
;
51 _finline CYFlags
CYCenter(CYFlags flags
) {
52 return CYLeft(CYRight(flags
));
55 void CYOutput::Terminate() {
60 CYOutput
&CYOutput::operator <<(char rhs
) {
61 if (rhs
== ' ' || rhs
== '\n')
67 for (unsigned i(0); i
!= indent_
; ++i
)
70 else if (rhs
== '\r') {
82 if (mode_
== Terminated
&& rhs
!= '}') {
94 } else if (rhs
== '+') {
98 } else if (rhs
== '-') {
99 if (mode_
== NoHyphen
)
102 } else if (WordEndRange_
[rhs
]) {
103 if (mode_
== NoLetter
)
115 CYOutput
&CYOutput::operator <<(const char *rhs
) {
116 size_t size(strlen(rhs
));
119 return *this << *rhs
;
121 if (mode_
== Terminated
)
124 mode_
== NoPlus
&& *rhs
== '+' ||
125 mode_
== NoHyphen
&& *rhs
== '-' ||
126 mode_
== NoLetter
&& WordEndRange_
[*rhs
]
130 if (WordEndRange_
[rhs
[size
- 1]])
140 void CYArgument::Output(CYOutput
&out
) const {
147 value_
->Output(out
, CYPA
, CYNoFlags
);
149 if (next_
->name_
== NULL
)
151 out
<< ' ' << *next_
;
155 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
156 out
<< '[' << elements_
<< ']';
159 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
160 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
163 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
164 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
165 out
<< ' ' << Operator() << ' ';
166 rhs_
->Output(out
, Precedence(), CYRight(flags
));
169 void CYBlock::Output(CYOutput
&out
) const {
172 if (statements_
!= NULL
)
173 statements_
->Multiple(out
);
178 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
179 if (statements_
== NULL
)
181 else if (statements_
->next_
== NULL
)
182 statements_
->Single(out
, flags
);
187 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
188 out
<< (Value() ? "true" : "false");
191 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
194 out
<< ' ' << *label_
;
198 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
199 bool protect((flags
& CYNoCall
) != 0);
202 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
203 out
<< '(' << arguments_
<< ')';
211 void Catch::Output(CYOutput
&out
) const {
212 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ' << code_
;
217 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
224 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
225 if (CYExpression
*expression
= expressions_
)
226 if (CYExpression
*next
= expression
->next_
) {
227 expression
->Output(out
, CYLeft(flags
));
228 CYFlags
center(CYCenter(flags
));
229 while (next
!= NULL
) {
232 next
= expression
->next_
;
233 CYFlags
right(next
!= NULL
? center
: CYRight(flags
));
234 expression
->Output(out
, right
);
237 expression
->Output(out
, flags
);
240 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
241 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
242 out
<< ' ' << '?' << ' ';
244 true_
->Output(out
, CYPA
, CYNoFlags
);
245 out
<< ' ' << ':' << ' ';
246 false_
->Output(out
, CYPA
, CYRight(flags
));
249 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
252 out
<< ' ' << *label_
;
256 void CYClause::Output(CYOutput
&out
) const {
258 out
<< "case" << ' ' << *case_
;
262 if (statements_
!= NULL
)
263 statements_
->Multiple(out
);
267 const char *CYDeclaration::ForEachIn() const {
268 return identifier_
->Word();
271 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
273 Output(out
, CYRight(flags
));
276 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
278 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
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
) | CYNoInteger
);
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 if (initialiser_
!= NULL
)
402 initialiser_
->ForIn(out
, CYNoIn
);
403 out
<< "in" << *set_
<< ')';
404 code_
->Single(out
, CYRight(flags
));
407 void CYForInComprehension::Output(CYOutput
&out
) const {
408 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
411 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
412 // XXX: one could imagine using + here to save a byte
413 bool protect((flags
& CYNoFunction
) != 0);
418 out
<< ' ' << *name_
;
419 out
<< '(' << parameters_
<< ')';
425 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
426 CYFunction::Output(out
, flags
);
429 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
430 CYFunction::Output(out
, flags
);
433 void CYFunctionParameter::Output(CYOutput
&out
) const {
436 out
<< ',' << ' ' << *next_
;
439 const char *CYIdentifier::Word() const {
440 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
443 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
445 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
450 out
<< "if" << ' ' << '(' << *test_
<< ')';
452 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
454 CYFlags
jacks(CYNoDangle
);
458 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
460 true_
->Single(out
, jacks
);
462 if (false_
!= NULL
) {
464 false_
->Single(out
, right
);
471 void CYIfComprehension::Output(CYOutput
&out
) const {
472 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
475 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
476 object_
->Output(out
, Precedence(), CYLeft(flags
));
477 if (const char *word
= property_
->Word())
480 out
<< "->" << '[' << *property_
<< ']';
483 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
484 const char *name(Operator());
485 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
488 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
489 lhs_
->Output(out
, Precedence(), left
);
490 out
<< ' ' << name
<< ' ';
491 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
492 rhs_
->Output(out
, Precedence() - 1, right
);
497 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
498 out
<< *name_
<< ':' << ' ';
499 statement_
->Single(out
, CYRight(flags
));
502 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
503 out
<< "let" << ' ' << '(' << *declarations_
<< ')' << ' ' << code_
;
509 void New::Output(CYOutput
&out
, CYFlags flags
) const {
511 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
512 constructor_
->Output(out
, Precedence(), jacks
);
513 if (arguments_
!= NULL
)
514 out
<< '(' << *arguments_
<< ')';
519 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
523 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
524 std::ostringstream str
;
525 CYNumerify(str
, Value());
526 std::string
value(str
.str());
527 out
<< value
.c_str();
528 // XXX: this should probably also handle hex conversions and exponents
529 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
533 void CYNumber::PropertyName(CYOutput
&out
) const {
534 Output(out
, CYNoFlags
);
537 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
538 bool protect((flags
& CYNoBrace
) != 0);
550 void CYOptionalFunctionParameter::Output(CYOutput
&out
) const {
551 out
<< *name_
<< '=';
552 initializer_
->Output(out
, CYPA
, CYNoFlags
);
554 out
<< ',' << ' ' << *next_
;
557 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
558 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
562 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
563 const char *name(Operator());
567 rhs_
->Output(out
, Precedence(), CYRight(flags
));
570 void CYProgram::Output(CYOutput
&out
) const {
571 if (statements_
!= NULL
)
572 statements_
->Multiple(out
);
575 void CYProperty::Output(CYOutput
&out
) const {
577 name_
->PropertyName(out
);
579 value_
->Output(out
, CYPA
, CYNoFlags
);
581 out
<< ',' << '\n' << *next_
;
586 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
590 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
593 out
<< ' ' << *value_
;
597 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
598 call_
->Output(out
, CYLeft(flags
));
600 proc_
->Output(out
, CYRight(flags
));
603 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
604 // XXX: this is not outputting the parameters
608 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
610 for (const CYStatement
*next(this); next
!= NULL
; next
= next
->next_
) {
611 bool last(next
->next_
== NULL
);
612 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
615 next
->Output(out
, jacks
);
620 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
621 _assert(next_
== NULL
);
630 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
631 std::ostringstream str
;
632 CYStringify(str
, value_
, size_
);
633 out
<< str
.str().c_str();
636 void CYString::PropertyName(CYOutput
&out
) const {
637 if (const char *word
= Word())
643 static const char *Reserved_
[] = {
644 "false", "null", "true",
646 "break", "case", "catch", "continue", "default",
647 "delete", "do", "else", "finally", "for", "function",
648 "if", "in", "instanceof", "new", "return", "switch",
649 "this", "throw", "try", "typeof", "var", "void",
654 "class", "enum", "export", "extends", "import", "super",
656 "abstract", "boolean", "byte", "char", "double", "final",
657 "float", "goto", "int", "long", "native", "short",
658 "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 {