]>
git.saurik.com Git - cycript.git/blob - Output.cpp
8d3ddaafbda38170c1e59e416d77482b8187fb07
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 void CYOutput::Terminate() {
32 CYOutput
&CYOutput::operator <<(char rhs
) {
33 if (rhs
== ' ' || rhs
== '\n')
39 for (unsigned i(0); i
!= indent_
; ++i
)
42 else if (rhs
== '\r') {
54 if (mode_
== Terminated
&& rhs
!= '}') {
66 } else if (rhs
== '+') {
70 } else if (rhs
== '-') {
71 if (mode_
== NoHyphen
)
74 } else if (WordEndRange_
[rhs
]) {
75 if (mode_
== NoLetter
)
87 CYOutput
&CYOutput::operator <<(const char *rhs
) {
88 size_t size(strlen(rhs
));
93 if (mode_
== Terminated
)
96 mode_
== NoPlus
&& *rhs
== '+' ||
97 mode_
== NoHyphen
&& *rhs
== '-' ||
98 mode_
== NoLetter
&& WordEndRange_
[*rhs
]
102 if (WordEndRange_
[rhs
[size
- 1]])
112 void CYArgument::Output(CYOutput
&out
) const {
119 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
121 if (next_
->name_
== NULL
)
123 out
<< ' ' << *next_
;
127 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
128 out
<< '[' << elements_
<< ']';
131 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
132 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
135 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
136 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
137 out
<< ' ' << Operator() << ' ';
138 rhs_
->Output(out
, Precedence(), CYRight(flags
));
141 void CYBlock::Output(CYOutput
&out
) const {
144 if (statements_
!= NULL
)
145 statements_
->Multiple(out
);
150 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
151 if (statements_
== NULL
)
153 else if (statements_
->next_
== NULL
)
154 statements_
->Single(out
, flags
);
159 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
160 out
<< (Value() ? "true" : "false");
163 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
166 out
<< ' ' << *label_
;
170 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
171 bool protect((flags
& CYNoCall
) != 0);
174 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
175 out
<< '(' << arguments_
<< ')';
183 void Catch::Output(CYOutput
&out
) const {
184 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ' << code_
;
189 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
196 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
197 if (CYExpression
*expression
= expressions_
)
198 if (CYExpression
*next
= expression
->next_
) {
199 expression
->Output(out
, CYLeft(flags
));
200 CYFlags
center(CYCenter(flags
));
201 while (next
!= NULL
) {
204 next
= expression
->next_
;
205 CYFlags
right(next
!= NULL
? center
: CYRight(flags
));
206 expression
->Output(out
, right
);
209 expression
->Output(out
, flags
);
212 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
213 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
214 out
<< ' ' << '?' << ' ';
216 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
217 out
<< ' ' << ':' << ' ';
218 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
221 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
224 out
<< ' ' << *label_
;
228 void CYClause::Output(CYOutput
&out
) const {
230 out
<< "case" << ' ' << *case_
;
234 if (statements_
!= NULL
)
235 statements_
->Multiple(out
);
239 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
241 Output(out
, CYRight(flags
));
244 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
246 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
247 if (initialiser_
!= NULL
) {
248 out
<< ' ' << '=' << ' ';
249 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
253 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
255 Output(out
, CYRight(flags
));
258 void CYDeclarations::Output(CYOutput
&out
) const {
259 Output(out
, CYNoFlags
);
262 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
263 const CYDeclarations
*declaration(this);
266 CYDeclarations
*next(declaration
->next_
);
267 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
269 declaration
->declaration_
->Output(out
, jacks
);
278 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
279 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
280 if (const char *word
= property_
->Word())
283 out
<< '[' << *property_
<< ']';
286 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
288 code_
->Single(out
, CYCenter(flags
));
289 out
<< "while" << ' ' << '(' << *test_
<< ')';
292 void CYElement::Output(CYOutput
&out
) const {
294 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
295 if (next_
!= NULL
|| value_
== NULL
) {
297 if (next_
!= NULL
&& next_
->value_
!= NULL
)
304 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
308 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
309 expression_
->Output(out
, flags
| CYNoBF
);
313 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
314 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
317 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
318 Output(out
, flags
| CYNoRightHand
);
321 void CYExpression::Output(CYOutput
&out
) const {
322 Output(out
, CYNoFlags
);
325 void CYExpression::Output(CYOutput
&out
, unsigned precedence
, CYFlags flags
) const {
326 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
327 out
<< '(' << *this << ')';
332 void CYFinally::Output(CYOutput
&out
) const {
333 out
<< ' ' << "finally" << ' ' << code_
;
336 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
337 out
<< "for" << ' ' << '(';
338 if (initialiser_
!= NULL
)
339 initialiser_
->Output(out
, CYNoIn
);
345 if (increment_
!= NULL
)
349 code_
->Single(out
, CYRight(flags
));
352 void CYForEachIn::Output(CYOutput
&out
, CYFlags flags
) const {
353 out
<< "for" << ' ' << "each" << ' ' << '(';
354 initialiser_
->ForIn(out
, CYNoIn
);
355 out
<< "in" << *set_
<< ')';
356 code_
->Single(out
, CYRight(flags
));
359 void CYForEachInComprehension::Output(CYOutput
&out
) const {
360 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
363 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
364 out
<< "for" << ' ' << '(';
365 if (initialiser_
!= NULL
)
366 initialiser_
->ForIn(out
, CYNoIn
);
367 out
<< "in" << *set_
<< ')';
368 code_
->Single(out
, CYRight(flags
));
371 void CYForInComprehension::Output(CYOutput
&out
) const {
372 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
375 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
376 // XXX: one could imagine using + here to save a byte
377 bool protect((flags
& CYNoFunction
) != 0);
382 out
<< ' ' << *name_
;
383 out
<< '(' << parameters_
<< ')';
389 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
390 CYFunction::Output(out
, flags
);
393 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
394 CYFunction::Output(out
, flags
);
397 void CYFunctionParameter::Output(CYOutput
&out
) const {
400 out
<< ',' << ' ' << *next_
;
403 const char *CYIdentifier::Word() const {
404 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
407 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
409 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
414 out
<< "if" << ' ' << '(' << *test_
<< ')';
416 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
418 CYFlags
jacks(CYNoDangle
);
422 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
424 true_
->Single(out
, jacks
);
426 if (false_
!= NULL
) {
427 out
<< '\t' << "else";
428 false_
->Single(out
, right
);
435 void CYIfComprehension::Output(CYOutput
&out
) const {
436 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
439 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
440 object_
->Output(out
, Precedence(), CYLeft(flags
));
441 if (const char *word
= property_
->Word())
444 out
<< "->" << '[' << *property_
<< ']';
447 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
448 const char *name(Operator());
449 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
452 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
453 lhs_
->Output(out
, Precedence(), left
);
454 out
<< ' ' << name
<< ' ';
455 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
456 rhs_
->Output(out
, Precedence() - 1, right
);
461 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
462 out
<< *name_
<< ':' << ' ';
463 statement_
->Single(out
, CYRight(flags
));
466 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
467 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
468 code_
->Single(out
, CYRight(flags
));
474 void New::Output(CYOutput
&out
, CYFlags flags
) const {
476 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
477 constructor_
->Output(out
, Precedence(), jacks
);
478 if (arguments_
!= NULL
)
479 out
<< '(' << *arguments_
<< ')';
484 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
488 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
489 std::ostringstream str
;
490 CYNumerify(str
, Value());
491 std::string
value(str
.str());
492 out
<< value
.c_str();
493 // XXX: this should probably also handle hex conversions and exponents
494 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
498 void CYNumber::PropertyName(CYOutput
&out
) const {
499 Output(out
, CYNoFlags
);
502 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
503 bool protect((flags
& CYNoBrace
) != 0);
515 void CYOptionalFunctionParameter::Output(CYOutput
&out
) const {
516 out
<< *name_
<< '=';
517 initializer_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
519 out
<< ',' << ' ' << *next_
;
522 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
523 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
527 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
528 const char *name(Operator());
532 rhs_
->Output(out
, Precedence(), CYRight(flags
));
535 void CYProgram::Output(CYOutput
&out
) const {
536 if (statements_
!= NULL
)
537 statements_
->Multiple(out
);
540 void CYProperty::Output(CYOutput
&out
) const {
542 name_
->PropertyName(out
);
544 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
546 out
<< ',' << '\n' << *next_
;
551 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
555 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
558 out
<< ' ' << *value_
;
562 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
563 call_
->Output(out
, CYLeft(flags
));
565 proc_
->Output(out
, CYRight(flags
));
568 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
569 // XXX: this is not outputting the parameters
573 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
575 CYForEach (next
, this) {
576 bool last(next
->next_
== NULL
);
577 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
580 next
->Output(out
, jacks
);
585 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
587 return out
.Terminate();
589 _assert(next_
== NULL
);
598 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
599 std::ostringstream str
;
600 CYStringify(str
, value_
, size_
);
601 out
<< str
.str().c_str();
604 void CYString::PropertyName(CYOutput
&out
) const {
605 if (const char *word
= Word())
611 static const char *Reserved_
[] = {
612 "false", "null", "true",
614 "break", "case", "catch", "continue", "default",
615 "delete", "do", "else", "finally", "for", "function",
616 "if", "in", "instanceof", "new", "return", "switch",
617 "this", "throw", "try", "typeof", "var", "void",
622 "class", "enum", "export", "extends", "import", "super",
624 "abstract", "boolean", "byte", "char", "double", "final",
625 "float", "goto", "int", "long", "native", "short",
626 "synchronized", "throws", "transient", "volatile",
633 const char *CYString::Word() const {
634 if (size_
== 0 || !WordStartRange_
[value_
[0]])
636 for (size_t i(1); i
!= size_
; ++i
)
637 if (!WordEndRange_
[value_
[i
]])
639 const char *value(Value());
640 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
641 if (strcmp(*reserved
, value
) == 0)
646 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
647 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
652 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
659 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
662 out
<< ' ' << *value_
;
666 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
667 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
672 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
674 declarations_
->Output(out
, flags
);
678 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
682 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
683 out
<< "while" << '(' << *test_
<< ')';
684 code_
->Single(out
, CYRight(flags
));
687 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
688 out
<< "with" << '(' << *scope_
<< ')';
689 code_
->Single(out
, CYRight(flags
));
692 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
694 out
<< "objc_getClass(";
695 out
<< '"' << Word() << '"';
700 void CYWord::Output(CYOutput
&out
) const {
702 if (out
.options_
.verbose_
)
703 out
.out_
<< '@' << this;
706 void CYWord::PropertyName(CYOutput
&out
) const {
710 const char *CYWord::Word() const {