]>
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() ? "0" : "1");
151 if ((flags
& CYNoInteger
) != 0)
155 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
158 out
<< ' ' << *label_
;
162 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
163 bool protect((flags
& CYNoCall
) != 0);
166 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
167 out
<< '(' << arguments_
<< ')';
175 void Catch::Output(CYOutput
&out
) const {
176 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ';
186 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
193 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
195 expression_
->Output(out
, flags
);
197 expression_
->Output(out
, CYLeft(flags
));
199 next_
->Output(out
, CYRight(flags
));
203 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
204 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
205 out
<< ' ' << '?' << ' ';
207 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
208 out
<< ' ' << ':' << ' ';
209 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
212 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
215 out
<< ' ' << *label_
;
219 void CYClause::Output(CYOutput
&out
) const {
222 out
<< "case" << ' ' << *case_
;
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 declarations_
->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 {
289 unsigned line(out
.position_
.line
);
290 unsigned indent(out
.indent_
);
291 code_
->Single(out
, CYCenter(flags
), CYCompactLong
);
293 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
298 out
<< "while" << ' ' << '(' << *test_
<< ')';
301 void CYElement::Output(CYOutput
&out
) const {
303 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
304 if (next_
!= NULL
|| value_
== NULL
) {
306 if (next_
!= NULL
&& next_
->value_
!= NULL
)
313 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
317 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
318 expression_
->Output(out
, flags
| CYNoBF
);
322 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
323 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
326 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
327 Output(out
, flags
| CYNoRightHand
);
330 void CYExpression::Output(CYOutput
&out
) const {
331 Output(out
, CYNoFlags
);
334 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
335 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
336 out
<< '(' << *this << ')';
341 void CYExternal::Output(CYOutput
&out
, CYFlags flags
) const {
342 out
<< "extern" << abi_
<< typed_
<< ';';
345 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
346 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << '{' << code_
<< '}';
349 void CYFinally::Output(CYOutput
&out
) const {
350 out
<< ' ' << "finally" << ' ';
358 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
359 out
<< "for" << ' ' << '(';
360 if (initialiser_
!= NULL
)
361 initialiser_
->Output(out
, CYNoIn
);
367 if (increment_
!= NULL
)
371 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
374 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
375 out
<< "for" << ' ' << "each" << ' ' << '(';
376 initialiser_
->ForIn(out
, CYNoIn
);
377 out
<< ' ' << "in" << ' ' << *set_
<< ')';
378 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
381 void CYForOfComprehension::Output(CYOutput
&out
) const {
382 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
385 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
386 out
<< "for" << ' ' << '(';
387 if (initialiser_
!= NULL
)
388 initialiser_
->ForIn(out
, CYNoIn
);
389 out
<< ' ' << "in" << ' ' << *set_
<< ')';
390 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
393 void CYForInComprehension::Output(CYOutput
&out
) const {
394 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
397 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
398 // XXX: one could imagine using + here to save a byte
399 bool protect((flags
& CYNoFunction
) != 0);
404 out
<< ' ' << *name_
;
405 out
<< '(' << parameters_
<< ')' << ' ';
415 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
416 CYFunction::Output(out
, flags
);
419 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
420 CYFunction::Output(out
, flags
);
423 void CYFunctionParameter::Output(CYOutput
&out
) const {
424 initialiser_
->Output(out
, CYNoFlags
);
426 out
<< ',' << ' ' << *next_
;
429 const char *CYIdentifier::Word() const {
430 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
433 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
435 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
440 out
<< "if" << ' ' << '(' << *test_
<< ')';
442 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
444 CYFlags
jacks(CYNoDangle
);
448 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
450 unsigned line(out
.position_
.line
);
451 unsigned indent(out
.indent_
);
452 true_
->Single(out
, jacks
, CYCompactShort
);
454 if (false_
!= NULL
) {
455 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
461 false_
->Single(out
, right
, CYCompactLong
);
468 void CYIfComprehension::Output(CYOutput
&out
) const {
469 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
472 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
476 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
477 object_
->Output(out
, Precedence(), CYLeft(flags
));
478 if (const char *word
= property_
->Word())
481 out
<< "->" << '[' << *property_
<< ']';
484 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
485 const char *name(Operator());
486 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
489 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
490 lhs_
->Output(out
, Precedence(), left
);
491 out
<< ' ' << name
<< ' ';
492 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
493 rhs_
->Output(out
, Precedence() - 1, right
);
498 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
499 out
<< *name_
<< ':';
500 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
503 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
505 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
509 void CYStatement::Output(CYOutput
&out
) const {
513 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
514 next_
->Output(out
, Precedence(), identifier
);
520 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
522 next_
->Output(out
, Precedence(), identifier
);
523 out
<< ')' << '(' << parameters_
<< ')';
526 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
527 out
<< "const" << ' ';
528 next_
->Output(out
, Precedence(), identifier
);
531 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
532 next_
->Output(out
, Precedence(), identifier
);
533 out
<< '(' << parameters_
<< ')';
536 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
538 next_
->Output(out
, Precedence(), identifier
);
541 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
543 next_
->Output(out
, Precedence(), identifier
);
546 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
552 bool protect(precedence
> Precedence());
556 Output(out
, identifier
);
561 void CYTypedIdentifier::Output(CYOutput
&out
) const {
562 specifier_
->Output(out
);
563 modifier_
->Output(out
, 0, identifier_
);
566 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
567 out
<< "@encode(" << typed_
<< ")";
570 void CYTypedParameter::Output(CYOutput
&out
) const {
573 out
<< ',' << ' ' << next_
;
576 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
577 // XXX: this is seriously wrong
584 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
585 out
<< "typedef" << ' ' << *typed_
;
588 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
589 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
590 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
593 void CYModule::Output(CYOutput
&out
) const {
602 void New::Output(CYOutput
&out
, CYFlags flags
) const {
604 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
605 constructor_
->Output(out
, Precedence(), jacks
);
606 if (arguments_
!= NULL
)
607 out
<< '(' << *arguments_
<< ')';
612 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
616 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
617 std::ostringstream str
;
618 CYNumerify(str
, Value());
619 std::string
value(str
.str());
620 out
<< value
.c_str();
621 // XXX: this should probably also handle hex conversions and exponents
622 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
626 void CYNumber::PropertyName(CYOutput
&out
) const {
627 Output(out
, CYNoFlags
);
630 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
631 bool protect((flags
& CYNoBrace
) != 0);
643 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
644 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
648 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
649 const char *name(Operator());
653 rhs_
->Output(out
, Precedence(), CYRight(flags
));
656 void CYProgram::Output(CYOutput
&out
) const {
660 void CYProperty::Output(CYOutput
&out
) const {
662 name_
->PropertyName(out
);
664 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
666 out
<< ',' << '\n' << *next_
;
671 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
675 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
678 out
<< ' ' << *value_
;
682 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
683 call_
->Output(out
, CYLeft(flags
));
685 proc_
->Output(out
, CYRight(flags
));
688 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
689 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
696 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
698 CYForEach (next
, this) {
699 bool last(next
->next_
== NULL
);
700 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
703 next
->Output(out
, jacks
);
708 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
710 return out
.Terminate();
712 _assert(next_
== NULL
);
714 CYCompactType
compact(Compact());
716 if (compact
>= request
)
726 if (compact
< request
)
730 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
731 std::ostringstream str
;
732 CYStringify(str
, value_
, size_
);
733 out
<< str
.str().c_str();
736 void CYString::PropertyName(CYOutput
&out
) const {
737 if (const char *word
= Word())
743 static const char *Reserved_
[] = {
744 "false", "null", "true",
746 "break", "case", "catch", "continue", "default",
747 "delete", "do", "else", "finally", "for", "function",
748 "if", "in", "instanceof", "new", "return", "switch",
749 "this", "throw", "try", "typeof", "var", "void",
754 "class", "enum", "export", "extends", "import", "super",
756 "abstract", "boolean", "byte", "char", "double", "final",
757 "float", "goto", "int", "long", "native", "short",
758 "synchronized", "throws", "transient", "volatile",
765 const char *CYString::Word() const {
766 if (size_
== 0 || !WordStartRange_
[value_
[0]])
768 for (size_t i(1); i
!= size_
; ++i
)
769 if (!WordEndRange_
[value_
[i
]])
771 const char *value(Value());
772 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
773 if (strcmp(*reserved
, value
) == 0)
778 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
779 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
786 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
793 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
796 out
<< ' ' << *value_
;
800 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
807 out
<< catch_
<< finally_
;
812 void CYTypeError::Output(CYOutput
&out
) const {
816 void CYTypeLong::Output(CYOutput
&out
) const {
817 out
<< "long" << specifier_
;
820 void CYTypeShort::Output(CYOutput
&out
) const {
821 out
<< "short" << specifier_
;
824 void CYTypeSigned::Output(CYOutput
&out
) const {
825 out
<< "signed" << specifier_
;
828 void CYTypeUnsigned::Output(CYOutput
&out
) const {
829 out
<< "unsigned" << specifier_
;
832 void CYTypeVariable::Output(CYOutput
&out
) const {
836 void CYTypeVoid::Output(CYOutput
&out
) const {
840 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
842 declarations_
->Output(out
, flags
);
846 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
850 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
851 out
<< "while" << ' ' << '(' << *test_
<< ')';
852 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
855 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
856 out
<< "with" << ' ' << '(' << *scope_
<< ')';
857 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
860 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
862 out
<< "objc_getClass(";
863 out
<< '"' << Word() << '"';
868 void CYWord::Output(CYOutput
&out
) const {
870 if (out
.options_
.verbose_
) {
873 sprintf(number
, "%p", this);
878 void CYWord::PropertyName(CYOutput
&out
) const {
882 const char *CYWord::Word() const {