]>
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 const char *CYDeclaration::ForEachIn() const {
240 return identifier_
->Word();
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 CYDeclarations::For(CYOutput
&out
) const {
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);
270 CYDeclarations
*next(declaration
->next_
);
271 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
273 declaration
->declaration_
->Output(out
, jacks
);
282 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
283 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
284 if (const char *word
= property_
->Word())
287 out
<< '[' << *property_
<< ']';
290 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
292 code_
->Single(out
, CYCenter(flags
));
293 out
<< "while" << ' ' << '(' << *test_
<< ')';
296 void CYElement::Output(CYOutput
&out
) const {
298 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
299 if (next_
!= NULL
|| value_
== NULL
) {
301 if (next_
!= NULL
&& next_
->value_
!= NULL
)
308 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
312 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
313 expression_
->Output(out
, flags
| CYNoBF
);
317 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
318 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
321 const char *CYExpression::ForEachIn() const {
325 void CYExpression::For(CYOutput
&out
) const {
329 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
330 Output(out
, flags
| CYNoRightHand
);
333 void CYExpression::Output(CYOutput
&out
) const {
334 Output(out
, CYNoFlags
);
337 void CYExpression::Output(CYOutput
&out
, unsigned precedence
, CYFlags flags
) const {
338 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
339 out
<< '(' << *this << ')';
344 void CYFinally::Output(CYOutput
&out
) const {
345 out
<< ' ' << "finally" << ' ' << code_
;
348 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
349 out
<< "for" << ' ' << '(';
350 if (initialiser_
!= NULL
)
351 initialiser_
->For(out
);
357 if (increment_
!= NULL
)
361 code_
->Single(out
, CYRight(flags
));
364 void CYForEachIn::Output(CYOutput
&out
, CYFlags flags
) const {
365 out
<< "for" << ' ' << "each" << ' ' << '(';
366 initialiser_
->ForIn(out
, CYNoIn
);
367 out
<< "in" << *set_
<< ')';
368 code_
->Single(out
, CYRight(flags
));
371 void CYForEachInComprehension::Output(CYOutput
&out
) const {
372 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
375 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
376 out
<< "for" << ' ' << '(';
377 if (initialiser_
!= NULL
)
378 initialiser_
->ForIn(out
, CYNoIn
);
379 out
<< "in" << *set_
<< ')';
380 code_
->Single(out
, CYRight(flags
));
383 void CYForInComprehension::Output(CYOutput
&out
) const {
384 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
387 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
388 // XXX: one could imagine using + here to save a byte
389 bool protect((flags
& CYNoFunction
) != 0);
394 out
<< ' ' << *name_
;
395 out
<< '(' << parameters_
<< ')';
401 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
402 CYFunction::Output(out
, flags
);
405 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
406 CYFunction::Output(out
, flags
);
409 void CYFunctionParameter::Output(CYOutput
&out
) const {
412 out
<< ',' << ' ' << *next_
;
415 const char *CYIdentifier::Word() const {
416 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
419 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
421 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
426 out
<< "if" << ' ' << '(' << *test_
<< ')';
428 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
430 CYFlags
jacks(CYNoDangle
);
434 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
436 true_
->Single(out
, jacks
);
438 if (false_
!= NULL
) {
439 out
<< '\t' << "else";
440 false_
->Single(out
, right
);
447 void CYIfComprehension::Output(CYOutput
&out
) const {
448 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
451 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
452 object_
->Output(out
, Precedence(), CYLeft(flags
));
453 if (const char *word
= property_
->Word())
456 out
<< "->" << '[' << *property_
<< ']';
459 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
460 const char *name(Operator());
461 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
464 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
465 lhs_
->Output(out
, Precedence(), left
);
466 out
<< ' ' << name
<< ' ';
467 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
468 rhs_
->Output(out
, Precedence() - 1, right
);
473 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
474 out
<< *name_
<< ':' << ' ';
475 statement_
->Single(out
, CYRight(flags
));
478 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
479 out
<< "let" << ' ' << '(' << *declarations_
<< ')' << ' ' << code_
;
485 void New::Output(CYOutput
&out
, CYFlags flags
) const {
487 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
488 constructor_
->Output(out
, Precedence(), jacks
);
489 if (arguments_
!= NULL
)
490 out
<< '(' << *arguments_
<< ')';
495 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
499 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
500 std::ostringstream str
;
501 CYNumerify(str
, Value());
502 std::string
value(str
.str());
503 out
<< value
.c_str();
504 // XXX: this should probably also handle hex conversions and exponents
505 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
509 void CYNumber::PropertyName(CYOutput
&out
) const {
510 Output(out
, CYNoFlags
);
513 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
514 bool protect((flags
& CYNoBrace
) != 0);
526 void CYOptionalFunctionParameter::Output(CYOutput
&out
) const {
527 out
<< *name_
<< '=';
528 initializer_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
530 out
<< ',' << ' ' << *next_
;
533 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
534 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
538 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
539 const char *name(Operator());
543 rhs_
->Output(out
, Precedence(), CYRight(flags
));
546 void CYProgram::Output(CYOutput
&out
) const {
547 if (statements_
!= NULL
)
548 statements_
->Multiple(out
);
551 void CYProperty::Output(CYOutput
&out
) const {
553 name_
->PropertyName(out
);
555 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
557 out
<< ',' << '\n' << *next_
;
562 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
566 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
569 out
<< ' ' << *value_
;
573 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
574 call_
->Output(out
, CYLeft(flags
));
576 proc_
->Output(out
, CYRight(flags
));
579 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
580 // XXX: this is not outputting the parameters
584 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
586 CYForEach (next
, this) {
587 bool last(next
->next_
== NULL
);
588 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
591 next
->Output(out
, jacks
);
596 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
597 _assert(next_
== NULL
);
606 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
607 std::ostringstream str
;
608 CYStringify(str
, value_
, size_
);
609 out
<< str
.str().c_str();
612 void CYString::PropertyName(CYOutput
&out
) const {
613 if (const char *word
= Word())
619 static const char *Reserved_
[] = {
620 "false", "null", "true",
622 "break", "case", "catch", "continue", "default",
623 "delete", "do", "else", "finally", "for", "function",
624 "if", "in", "instanceof", "new", "return", "switch",
625 "this", "throw", "try", "typeof", "var", "void",
630 "class", "enum", "export", "extends", "import", "super",
632 "abstract", "boolean", "byte", "char", "double", "final",
633 "float", "goto", "int", "long", "native", "short",
634 "synchronized", "throws", "transient", "volatile",
641 const char *CYString::Word() const {
642 if (size_
== 0 || !WordStartRange_
[value_
[0]])
644 for (size_t i(1); i
!= size_
; ++i
)
645 if (!WordEndRange_
[value_
[i
]])
647 const char *value(Value());
648 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
649 if (strcmp(*reserved
, value
) == 0)
654 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
655 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
660 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
667 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
670 out
<< ' ' << *value_
;
674 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
675 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
680 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
682 declarations_
->Output(out
, flags
);
686 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
690 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
691 out
<< "while" << '(' << *test_
<< ')';
692 code_
->Single(out
, CYRight(flags
));
695 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
696 out
<< "with" << '(' << *scope_
<< ')';
697 code_
->Single(out
, CYRight(flags
));
700 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
702 out
<< "objc_getClass(";
703 out
<< '"' << Word() << '"';
708 void CYWord::Output(CYOutput
&out
) const {
710 if (out
.options_
.verbose_
)
711 out
.out_
<< '@' << this;
714 void CYWord::PropertyName(CYOutput
&out
) const {
718 const char *CYWord::Word() const {