]>
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 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 CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
240 out
<< "debugger" << ';';
243 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
245 Output(out
, CYRight(flags
));
248 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
250 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
251 if (initialiser_
!= NULL
) {
252 out
<< ' ' << '=' << ' ';
253 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
257 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
259 Output(out
, CYRight(flags
));
262 void CYDeclarations::Output(CYOutput
&out
) const {
263 Output(out
, CYNoFlags
);
266 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
267 const CYDeclarations
*declaration(this);
271 CYDeclarations
*next(declaration
->next_
);
273 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
275 declaration
->declaration_
->Output(out
, jacks
);
285 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
286 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
287 if (const char *word
= property_
->Word())
290 out
<< '[' << *property_
<< ']';
293 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
295 code_
->Single(out
, CYCenter(flags
));
296 out
<< "while" << ' ' << '(' << *test_
<< ')';
299 void CYElement::Output(CYOutput
&out
) const {
301 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
302 if (next_
!= NULL
|| value_
== NULL
) {
304 if (next_
!= NULL
&& next_
->value_
!= NULL
)
311 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
315 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
316 expression_
->Output(out
, flags
| CYNoBF
);
320 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
321 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
324 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
325 Output(out
, flags
| CYNoRightHand
);
328 void CYExpression::Output(CYOutput
&out
) const {
329 Output(out
, CYNoFlags
);
332 void CYExpression::Output(CYOutput
&out
, unsigned precedence
, CYFlags flags
) const {
333 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
334 out
<< '(' << *this << ')';
339 void CYFinally::Output(CYOutput
&out
) const {
340 out
<< ' ' << "finally" << ' ' << code_
;
343 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
344 out
<< "for" << ' ' << '(';
345 if (initialiser_
!= NULL
)
346 initialiser_
->Output(out
, CYNoIn
);
352 if (increment_
!= NULL
)
356 code_
->Single(out
, CYRight(flags
));
359 void CYForEachIn::Output(CYOutput
&out
, CYFlags flags
) const {
360 out
<< "for" << ' ' << "each" << ' ' << '(';
361 initialiser_
->ForIn(out
, CYNoIn
);
362 out
<< "in" << *set_
<< ')';
363 code_
->Single(out
, CYRight(flags
));
366 void CYForEachInComprehension::Output(CYOutput
&out
) const {
367 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
370 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
371 out
<< "for" << ' ' << '(';
372 if (initialiser_
!= NULL
)
373 initialiser_
->ForIn(out
, CYNoIn
);
374 out
<< "in" << *set_
<< ')';
375 code_
->Single(out
, CYRight(flags
));
378 void CYForInComprehension::Output(CYOutput
&out
) const {
379 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
382 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
383 // XXX: one could imagine using + here to save a byte
384 bool protect((flags
& CYNoFunction
) != 0);
389 out
<< ' ' << *name_
;
390 out
<< '(' << parameters_
<< ')';
396 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
397 CYFunction::Output(out
, flags
);
400 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
401 CYFunction::Output(out
, flags
);
404 void CYFunctionParameter::Output(CYOutput
&out
) const {
405 initialiser_
->Output(out
, CYNoFlags
);
407 out
<< ',' << ' ' << *next_
;
410 const char *CYIdentifier::Word() const {
411 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
414 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
416 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
421 out
<< "if" << ' ' << '(' << *test_
<< ')';
423 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
425 CYFlags
jacks(CYNoDangle
);
429 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
431 true_
->Single(out
, jacks
);
433 if (false_
!= NULL
) {
434 out
<< '\t' << "else";
435 false_
->Single(out
, right
);
442 void CYIfComprehension::Output(CYOutput
&out
) const {
443 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
446 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
447 object_
->Output(out
, Precedence(), CYLeft(flags
));
448 if (const char *word
= property_
->Word())
451 out
<< "->" << '[' << *property_
<< ']';
454 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
455 const char *name(Operator());
456 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
459 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
460 lhs_
->Output(out
, Precedence(), left
);
461 out
<< ' ' << name
<< ' ';
462 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
463 rhs_
->Output(out
, Precedence() - 1, right
);
468 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
469 out
<< *name_
<< ':' << ' ';
470 statement_
->Single(out
, CYRight(flags
));
473 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
474 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
475 code_
->Single(out
, CYRight(flags
));
481 void New::Output(CYOutput
&out
, CYFlags flags
) const {
483 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
484 constructor_
->Output(out
, Precedence(), jacks
);
485 if (arguments_
!= NULL
)
486 out
<< '(' << *arguments_
<< ')';
491 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
495 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
496 std::ostringstream str
;
497 CYNumerify(str
, Value());
498 std::string
value(str
.str());
499 out
<< value
.c_str();
500 // XXX: this should probably also handle hex conversions and exponents
501 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
505 void CYNumber::PropertyName(CYOutput
&out
) const {
506 Output(out
, CYNoFlags
);
509 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
510 bool protect((flags
& CYNoBrace
) != 0);
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 {