]>
git.saurik.com Git - cycript.git/blob - Output.cpp
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 // XXX: this is not outputting the parameters
695 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
697 CYForEach (next
, this) {
698 bool last(next
->next_
== NULL
);
699 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
702 next
->Output(out
, jacks
);
707 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
709 return out
.Terminate();
711 _assert(next_
== NULL
);
713 CYCompactType
compact(Compact());
715 if (compact
>= request
)
725 if (compact
< request
)
729 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
730 std::ostringstream str
;
731 CYStringify(str
, value_
, size_
);
732 out
<< str
.str().c_str();
735 void CYString::PropertyName(CYOutput
&out
) const {
736 if (const char *word
= Word())
742 static const char *Reserved_
[] = {
743 "false", "null", "true",
745 "break", "case", "catch", "continue", "default",
746 "delete", "do", "else", "finally", "for", "function",
747 "if", "in", "instanceof", "new", "return", "switch",
748 "this", "throw", "try", "typeof", "var", "void",
753 "class", "enum", "export", "extends", "import", "super",
755 "abstract", "boolean", "byte", "char", "double", "final",
756 "float", "goto", "int", "long", "native", "short",
757 "synchronized", "throws", "transient", "volatile",
764 const char *CYString::Word() const {
765 if (size_
== 0 || !WordStartRange_
[value_
[0]])
767 for (size_t i(1); i
!= size_
; ++i
)
768 if (!WordEndRange_
[value_
[i
]])
770 const char *value(Value());
771 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
772 if (strcmp(*reserved
, value
) == 0)
777 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
778 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
785 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
792 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
795 out
<< ' ' << *value_
;
799 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
806 out
<< catch_
<< finally_
;
811 void CYTypeError::Output(CYOutput
&out
) const {
815 void CYTypeLong::Output(CYOutput
&out
) const {
816 out
<< "long" << specifier_
;
819 void CYTypeShort::Output(CYOutput
&out
) const {
820 out
<< "short" << specifier_
;
823 void CYTypeSigned::Output(CYOutput
&out
) const {
824 out
<< "signed" << specifier_
;
827 void CYTypeUnsigned::Output(CYOutput
&out
) const {
828 out
<< "unsigned" << specifier_
;
831 void CYTypeVariable::Output(CYOutput
&out
) const {
835 void CYTypeVoid::Output(CYOutput
&out
) const {
839 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
841 declarations_
->Output(out
, flags
);
845 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
849 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
850 out
<< "while" << ' ' << '(' << *test_
<< ')';
851 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
854 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
855 out
<< "with" << ' ' << '(' << *scope_
<< ')';
856 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
859 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
861 out
<< "objc_getClass(";
862 out
<< '"' << Word() << '"';
867 void CYWord::Output(CYOutput
&out
) const {
869 if (out
.options_
.verbose_
) {
872 sprintf(number
, "%p", this);
877 void CYWord::PropertyName(CYOutput
&out
) const {
881 const char *CYWord::Word() const {