]>
git.saurik.com Git - cycript.git/blob - Output.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2014 Jay Freeman (saurik)
5 /* GNU Affero General Public License, Version 3 {{{ */
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. 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
);
122 out
<< ' ' << *next_
;
126 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
127 out
<< '[' << elements_
<< ']';
130 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
131 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
134 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
135 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
136 out
<< ' ' << Operator() << ' ';
137 rhs_
->Output(out
, Precedence(), CYRight(flags
));
140 void CYBlock::Output(CYOutput
&out
) const {
143 if (statements_
!= NULL
)
144 statements_
->Multiple(out
);
149 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
150 if (statements_
== NULL
)
152 else if (statements_
->next_
== NULL
)
153 statements_
->Single(out
, flags
);
158 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
159 out
<< (Value() ? "true" : "false");
162 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
165 out
<< ' ' << *label_
;
169 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
170 bool protect((flags
& CYNoCall
) != 0);
173 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
174 out
<< '(' << arguments_
<< ')';
182 void Catch::Output(CYOutput
&out
) const {
183 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ' << code_
;
188 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
195 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
197 expression_
->Output(out
, flags
);
199 expression_
->Output(out
, CYLeft(flags
));
201 next_
->Output(out
, CYRight(flags
));
205 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
206 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
207 out
<< ' ' << '?' << ' ';
209 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
210 out
<< ' ' << ':' << ' ';
211 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
214 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
217 out
<< ' ' << *label_
;
221 void CYClause::Output(CYOutput
&out
) const {
223 out
<< "case" << ' ' << *case_
;
227 if (statements_
!= NULL
)
228 statements_
->Multiple(out
);
232 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
233 out
<< "debugger" << ';';
236 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
238 Output(out
, CYRight(flags
));
241 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
243 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
244 if (initialiser_
!= NULL
) {
245 out
<< ' ' << '=' << ' ';
246 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
250 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
252 Output(out
, CYRight(flags
));
255 void CYDeclarations::Output(CYOutput
&out
) const {
256 Output(out
, CYNoFlags
);
259 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
260 const CYDeclarations
*declaration(this);
264 CYDeclarations
*next(declaration
->next_
);
266 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
268 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
, int precedence
, CYFlags flags
) const {
326 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
327 out
<< '(' << *this << ')';
332 void CYExternal::Output(CYOutput
&out
, CYFlags flags
) const {
333 out
<< "extern" << abi_
<< typed_
<< ';';
336 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
337 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << code_
;
340 void CYFinally::Output(CYOutput
&out
) const {
341 out
<< ' ' << "finally" << ' ' << code_
;
344 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
345 out
<< "for" << ' ' << '(';
346 if (initialiser_
!= NULL
)
347 initialiser_
->Output(out
, CYNoIn
);
353 if (increment_
!= NULL
)
357 code_
->Single(out
, CYRight(flags
));
360 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
361 out
<< "for" << ' ' << "each" << ' ' << '(';
362 initialiser_
->ForIn(out
, CYNoIn
);
363 out
<< "in" << *set_
<< ')';
364 code_
->Single(out
, CYRight(flags
));
367 void CYForOfComprehension::Output(CYOutput
&out
) const {
368 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
371 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
372 out
<< "for" << ' ' << '(';
373 if (initialiser_
!= NULL
)
374 initialiser_
->ForIn(out
, CYNoIn
);
375 out
<< "in" << *set_
<< ')';
376 code_
->Single(out
, CYRight(flags
));
379 void CYForInComprehension::Output(CYOutput
&out
) const {
380 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
383 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
384 // XXX: one could imagine using + here to save a byte
385 bool protect((flags
& CYNoFunction
) != 0);
390 out
<< ' ' << *name_
;
391 out
<< '(' << parameters_
<< ')';
397 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
398 CYFunction::Output(out
, flags
);
401 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
402 CYFunction::Output(out
, flags
);
405 void CYFunctionParameter::Output(CYOutput
&out
) const {
406 initialiser_
->Output(out
, CYNoFlags
);
408 out
<< ',' << ' ' << *next_
;
411 const char *CYIdentifier::Word() const {
412 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
415 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
417 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
422 out
<< "if" << ' ' << '(' << *test_
<< ')';
424 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
426 CYFlags
jacks(CYNoDangle
);
430 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
432 true_
->Single(out
, jacks
);
434 if (false_
!= NULL
) {
435 out
<< '\t' << "else";
436 false_
->Single(out
, right
);
443 void CYIfComprehension::Output(CYOutput
&out
) const {
444 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
447 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
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 CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
479 next_
->Output(out
, Precedence(), identifier
);
485 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
487 next_
->Output(out
, Precedence(), identifier
);
488 out
<< ')' << '(' << parameters_
<< ')';
491 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
493 next_
->Output(out
, Precedence(), identifier
);
496 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
497 next_
->Output(out
, Precedence(), identifier
);
498 out
<< '(' << parameters_
<< ')';
501 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
503 next_
->Output(out
, Precedence(), identifier
);
506 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
508 next_
->Output(out
, Precedence(), identifier
);
511 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
517 bool protect(precedence
> Precedence());
521 Output(out
, identifier
);
526 void CYTypedIdentifier::Output(CYOutput
&out
) const {
527 specifier_
->Output(out
);
528 modifier_
->Output(out
, 0, identifier_
);
531 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
532 out
<< "@encode(" << typed_
<< ")";
535 void CYTypedParameter::Output(CYOutput
&out
) const {
538 out
<< ',' << ' ' << next_
;
541 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
542 // XXX: this is seriously wrong
549 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
550 out
<< "typedef" << *typed_
;
553 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
554 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
555 code_
->Single(out
, CYRight(flags
));
558 void CYModule::Output(CYOutput
&out
) const {
567 void New::Output(CYOutput
&out
, CYFlags flags
) const {
569 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
570 constructor_
->Output(out
, Precedence(), jacks
);
571 if (arguments_
!= NULL
)
572 out
<< '(' << *arguments_
<< ')';
577 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
581 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
582 std::ostringstream str
;
583 CYNumerify(str
, Value());
584 std::string
value(str
.str());
585 out
<< value
.c_str();
586 // XXX: this should probably also handle hex conversions and exponents
587 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
591 void CYNumber::PropertyName(CYOutput
&out
) const {
592 Output(out
, CYNoFlags
);
595 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
596 bool protect((flags
& CYNoBrace
) != 0);
608 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
609 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
613 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
614 const char *name(Operator());
618 rhs_
->Output(out
, Precedence(), CYRight(flags
));
621 void CYProgram::Output(CYOutput
&out
) const {
622 if (statements_
!= NULL
)
623 statements_
->Multiple(out
);
626 void CYProperty::Output(CYOutput
&out
) const {
628 name_
->PropertyName(out
);
630 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
632 out
<< ',' << '\n' << *next_
;
637 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
641 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
644 out
<< ' ' << *value_
;
648 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
649 call_
->Output(out
, CYLeft(flags
));
651 proc_
->Output(out
, CYRight(flags
));
654 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
655 // XXX: this is not outputting the parameters
659 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
661 CYForEach (next
, this) {
662 bool last(next
->next_
== NULL
);
663 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
666 next
->Output(out
, jacks
);
671 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
673 return out
.Terminate();
675 _assert(next_
== NULL
);
684 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
685 std::ostringstream str
;
686 CYStringify(str
, value_
, size_
);
687 out
<< str
.str().c_str();
690 void CYString::PropertyName(CYOutput
&out
) const {
691 if (const char *word
= Word())
697 static const char *Reserved_
[] = {
698 "false", "null", "true",
700 "break", "case", "catch", "continue", "default",
701 "delete", "do", "else", "finally", "for", "function",
702 "if", "in", "instanceof", "new", "return", "switch",
703 "this", "throw", "try", "typeof", "var", "void",
708 "class", "enum", "export", "extends", "import", "super",
710 "abstract", "boolean", "byte", "char", "double", "final",
711 "float", "goto", "int", "long", "native", "short",
712 "synchronized", "throws", "transient", "volatile",
719 const char *CYString::Word() const {
720 if (size_
== 0 || !WordStartRange_
[value_
[0]])
722 for (size_t i(1); i
!= size_
; ++i
)
723 if (!WordEndRange_
[value_
[i
]])
725 const char *value(Value());
726 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
727 if (strcmp(*reserved
, value
) == 0)
732 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
733 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
738 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
745 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
748 out
<< ' ' << *value_
;
752 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
753 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
758 void CYTypeError::Output(CYOutput
&out
) const {
762 void CYTypeLong::Output(CYOutput
&out
) const {
763 out
<< "long" << specifier_
;
766 void CYTypeShort::Output(CYOutput
&out
) const {
767 out
<< "short" << specifier_
;
770 void CYTypeSigned::Output(CYOutput
&out
) const {
771 out
<< "signed" << specifier_
;
774 void CYTypeUnsigned::Output(CYOutput
&out
) const {
775 out
<< "unsigned" << specifier_
;
778 void CYTypeVariable::Output(CYOutput
&out
) const {
782 void CYTypeVoid::Output(CYOutput
&out
) const {
786 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
788 declarations_
->Output(out
, flags
);
792 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
796 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
797 out
<< "while" << '(' << *test_
<< ')';
798 code_
->Single(out
, CYRight(flags
));
801 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
802 out
<< "with" << '(' << *scope_
<< ')';
803 code_
->Single(out
, CYRight(flags
));
806 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
808 out
<< "objc_getClass(";
809 out
<< '"' << Word() << '"';
814 void CYWord::Output(CYOutput
&out
) const {
816 if (out
.options_
.verbose_
)
817 out
.out_
<< '@' << this;
820 void CYWord::PropertyName(CYOutput
&out
) const {
824 const char *CYWord::Word() const {