]>
git.saurik.com Git - cycript.git/blob - Output.cpp
d45a7397489e928d45471a4501acea9f23b3c809
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 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 char last(rhs
[size
- 1]);
103 if (WordEndRange_
[last
] || last
== '/')
109 operator ()(rhs
, size
);
113 void CYArgument::Output(CYOutput
&out
) const {
120 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
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
, CYFlags flags
) const {
149 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
150 out
<< (Value() ? "true" : "false");
153 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
156 out
<< ' ' << *label_
;
160 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
161 bool protect((flags
& CYNoCall
) != 0);
164 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
165 out
<< '(' << arguments_
<< ')';
173 void Catch::Output(CYOutput
&out
) const {
174 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ';
184 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
191 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
193 expression_
->Output(out
, flags
);
195 expression_
->Output(out
, CYLeft(flags
));
197 next_
->Output(out
, CYRight(flags
));
201 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
202 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
203 out
<< ' ' << '?' << ' ';
205 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
206 out
<< ' ' << ':' << ' ';
207 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
210 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
213 out
<< ' ' << *label_
;
217 void CYClause::Output(CYOutput
&out
) const {
220 out
<< "case" << ' ' << *case_
;
230 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
231 out
<< "debugger" << ';';
234 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
236 Output(out
, CYRight(flags
));
239 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
241 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
242 if (initialiser_
!= NULL
) {
243 out
<< ' ' << '=' << ' ';
244 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
248 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
250 declarations_
->Output(out
, CYRight(flags
));
253 void CYDeclarations::Output(CYOutput
&out
) const {
254 Output(out
, CYNoFlags
);
257 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
258 const CYDeclarations
*declaration(this);
262 CYDeclarations
*next(declaration
->next_
);
264 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
266 declaration
->declaration_
->Output(out
, jacks
);
276 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
277 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
278 if (const char *word
= property_
->Word())
281 out
<< '[' << *property_
<< ']';
284 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
287 unsigned line(out
.position_
.line
);
288 unsigned indent(out
.indent_
);
289 code_
->Single(out
, CYCenter(flags
), CYCompactLong
);
291 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
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
, int precedence
, CYFlags flags
) const {
333 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
334 out
<< '(' << *this << ')';
339 void CYExternal::Output(CYOutput
&out
, CYFlags flags
) const {
340 out
<< "extern" << abi_
<< typed_
<< ';';
343 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
344 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << '{' << code_
<< '}';
347 void CYFinally::Output(CYOutput
&out
) const {
348 out
<< ' ' << "finally" << ' ';
356 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
357 out
<< "for" << ' ' << '(';
358 if (initialiser_
!= NULL
)
359 initialiser_
->Output(out
, CYNoIn
);
365 if (increment_
!= NULL
)
369 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
372 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
373 out
<< "for" << ' ' << "each" << ' ' << '(';
374 initialiser_
->ForIn(out
, CYNoIn
);
375 out
<< ' ' << "in" << ' ' << *set_
<< ')';
376 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
379 void CYForOfComprehension::Output(CYOutput
&out
) const {
380 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
383 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
384 out
<< "for" << ' ' << '(';
385 if (initialiser_
!= NULL
)
386 initialiser_
->ForIn(out
, CYNoIn
);
387 out
<< ' ' << "in" << ' ' << *set_
<< ')';
388 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
391 void CYForInComprehension::Output(CYOutput
&out
) const {
392 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
395 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
396 // XXX: one could imagine using + here to save a byte
397 bool protect((flags
& CYNoFunction
) != 0);
402 out
<< ' ' << *name_
;
403 out
<< '(' << parameters_
<< ')' << ' ';
413 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
414 CYFunction::Output(out
, flags
);
417 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
418 CYFunction::Output(out
, flags
);
421 void CYFunctionParameter::Output(CYOutput
&out
) const {
422 initialiser_
->Output(out
, CYNoFlags
);
424 out
<< ',' << ' ' << *next_
;
427 const char *CYIdentifier::Word() const {
428 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
431 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
433 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
438 out
<< "if" << ' ' << '(' << *test_
<< ')';
440 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
442 CYFlags
jacks(CYNoDangle
);
446 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
448 unsigned line(out
.position_
.line
);
449 unsigned indent(out
.indent_
);
450 true_
->Single(out
, jacks
, CYCompactShort
);
452 if (false_
!= NULL
) {
453 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
459 false_
->Single(out
, right
, CYCompactLong
);
466 void CYIfComprehension::Output(CYOutput
&out
) const {
467 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
470 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
474 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
475 object_
->Output(out
, Precedence(), CYLeft(flags
));
476 if (const char *word
= property_
->Word())
479 out
<< "->" << '[' << *property_
<< ']';
482 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
483 const char *name(Operator());
484 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
487 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
488 lhs_
->Output(out
, Precedence(), left
);
489 out
<< ' ' << name
<< ' ';
490 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
491 rhs_
->Output(out
, Precedence() - 1, right
);
496 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
497 out
<< *name_
<< ':';
498 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
501 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
503 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
507 void CYStatement::Output(CYOutput
&out
) const {
511 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
512 next_
->Output(out
, Precedence(), identifier
);
518 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
520 next_
->Output(out
, Precedence(), identifier
);
521 out
<< ')' << '(' << parameters_
<< ')';
524 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
525 out
<< "const" << ' ';
526 next_
->Output(out
, Precedence(), identifier
);
529 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
530 next_
->Output(out
, Precedence(), identifier
);
531 out
<< '(' << parameters_
<< ')';
534 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
536 next_
->Output(out
, Precedence(), identifier
);
539 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
541 next_
->Output(out
, Precedence(), identifier
);
544 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
550 bool protect(precedence
> Precedence());
554 Output(out
, identifier
);
559 void CYTypedIdentifier::Output(CYOutput
&out
) const {
560 specifier_
->Output(out
);
561 modifier_
->Output(out
, 0, identifier_
);
564 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
565 out
<< "@encode(" << typed_
<< ")";
568 void CYTypedParameter::Output(CYOutput
&out
) const {
571 out
<< ',' << ' ' << next_
;
574 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
575 // XXX: this is seriously wrong
582 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
583 out
<< "typedef" << ' ' << *typed_
;
586 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
587 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
588 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
591 void CYModule::Output(CYOutput
&out
) const {
600 void New::Output(CYOutput
&out
, CYFlags flags
) const {
602 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
603 constructor_
->Output(out
, Precedence(), jacks
);
604 if (arguments_
!= NULL
)
605 out
<< '(' << *arguments_
<< ')';
610 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
614 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
615 std::ostringstream str
;
616 CYNumerify(str
, Value());
617 std::string
value(str
.str());
618 out
<< value
.c_str();
619 // XXX: this should probably also handle hex conversions and exponents
620 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
624 void CYNumber::PropertyName(CYOutput
&out
) const {
625 Output(out
, CYNoFlags
);
628 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
629 bool protect((flags
& CYNoBrace
) != 0);
641 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
642 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
646 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
647 const char *name(Operator());
651 rhs_
->Output(out
, Precedence(), CYRight(flags
));
654 void CYProgram::Output(CYOutput
&out
) const {
658 void CYProperty::Output(CYOutput
&out
) const {
660 name_
->PropertyName(out
);
662 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
664 out
<< ',' << '\n' << *next_
;
669 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
673 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
676 out
<< ' ' << *value_
;
680 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
681 call_
->Output(out
, CYLeft(flags
));
683 proc_
->Output(out
, CYRight(flags
));
686 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
687 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
694 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
696 CYForEach (next
, this) {
697 bool last(next
->next_
== NULL
);
698 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
701 next
->Output(out
, jacks
);
706 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
708 return out
.Terminate();
710 _assert(next_
== NULL
);
712 CYCompactType
compact(Compact());
714 if (compact
>= request
)
724 if (compact
< request
)
728 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
729 std::ostringstream str
;
730 CYStringify(str
, value_
, size_
);
731 out
<< str
.str().c_str();
734 void CYString::PropertyName(CYOutput
&out
) const {
735 if (const char *word
= Word())
741 static const char *Reserved_
[] = {
742 "false", "null", "true",
744 "break", "case", "catch", "continue", "default",
745 "delete", "do", "else", "finally", "for", "function",
746 "if", "in", "instanceof", "new", "return", "switch",
747 "this", "throw", "try", "typeof", "var", "void",
752 "class", "enum", "export", "extends", "import", "super",
754 "abstract", "boolean", "byte", "char", "double", "final",
755 "float", "goto", "int", "long", "native", "short",
756 "synchronized", "throws", "transient", "volatile",
763 const char *CYString::Word() const {
764 if (size_
== 0 || !WordStartRange_
[value_
[0]])
766 for (size_t i(1); i
!= size_
; ++i
)
767 if (!WordEndRange_
[value_
[i
]])
769 const char *value(Value());
770 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
771 if (strcmp(*reserved
, value
) == 0)
776 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
777 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
784 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
791 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
794 out
<< ' ' << *value_
;
798 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
805 out
<< catch_
<< finally_
;
810 void CYTypeError::Output(CYOutput
&out
) const {
814 void CYTypeLong::Output(CYOutput
&out
) const {
815 out
<< "long" << specifier_
;
818 void CYTypeShort::Output(CYOutput
&out
) const {
819 out
<< "short" << specifier_
;
822 void CYTypeSigned::Output(CYOutput
&out
) const {
823 out
<< "signed" << specifier_
;
826 void CYTypeUnsigned::Output(CYOutput
&out
) const {
827 out
<< "unsigned" << specifier_
;
830 void CYTypeVariable::Output(CYOutput
&out
) const {
834 void CYTypeVoid::Output(CYOutput
&out
) const {
838 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
840 declarations_
->Output(out
, flags
);
844 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
848 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
849 out
<< "while" << ' ' << '(' << *test_
<< ')';
850 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
853 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
854 out
<< "with" << ' ' << '(' << *scope_
<< ')';
855 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
858 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
860 out
<< "objc_getClass(";
861 out
<< '"' << Word() << '"';
866 void CYWord::Output(CYOutput
&out
) const {
868 if (out
.options_
.verbose_
) {
871 sprintf(number
, "%p", this);
876 void CYWord::PropertyName(CYOutput
&out
) const {
880 const char *CYWord::Word() const {