]>
git.saurik.com Git - cycript.git/blob - Output.cpp
9ec05c2044e100057f8c43489dbf7545add0ccaa
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 CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
188 expression_
->Output(out
, flags
);
190 expression_
->Output(out
, CYLeft(flags
));
192 next_
->Output(out
, CYRight(flags
));
196 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
197 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
198 out
<< ' ' << '?' << ' ';
200 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
201 out
<< ' ' << ':' << ' ';
202 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
205 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
208 out
<< ' ' << *label_
;
212 void CYClause::Output(CYOutput
&out
) const {
215 out
<< "case" << ' ' << *case_
;
225 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
226 out
<< "debugger" << ';';
229 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
231 Output(out
, CYRight(flags
));
234 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
236 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
237 if (initialiser_
!= NULL
) {
238 out
<< ' ' << '=' << ' ';
239 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
243 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
245 declarations_
->Output(out
, CYRight(flags
));
248 void CYDeclarations::Output(CYOutput
&out
) const {
249 Output(out
, CYNoFlags
);
252 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
253 const CYDeclarations
*declaration(this);
257 CYDeclarations
*next(declaration
->next_
);
259 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
261 declaration
->declaration_
->Output(out
, jacks
);
271 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
272 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
273 if (const char *word
= property_
->Word())
276 out
<< '[' << *property_
<< ']';
279 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
282 unsigned line(out
.position_
.line
);
283 unsigned indent(out
.indent_
);
284 code_
->Single(out
, CYCenter(flags
), CYCompactLong
);
286 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
291 out
<< "while" << ' ' << '(' << *test_
<< ')';
294 void CYElement::Output(CYOutput
&out
) const {
296 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
297 if (next_
!= NULL
|| value_
== NULL
) {
299 if (next_
!= NULL
&& next_
->value_
!= NULL
)
306 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
310 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
311 expression_
->Output(out
, flags
| CYNoBF
);
315 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
316 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
319 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
320 Output(out
, flags
| CYNoRightHand
);
323 void CYExpression::Output(CYOutput
&out
) const {
324 Output(out
, CYNoFlags
);
327 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
328 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
329 out
<< '(' << *this << ')';
334 void CYExternal::Output(CYOutput
&out
, CYFlags flags
) const {
335 out
<< "extern" << abi_
<< typed_
<< ';';
338 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
339 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << '{' << code_
<< '}';
342 void CYFinally::Output(CYOutput
&out
) const {
343 out
<< ' ' << "finally" << ' ';
351 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
352 out
<< "for" << ' ' << '(';
353 if (initialiser_
!= NULL
)
354 initialiser_
->Output(out
, CYNoIn
);
360 if (increment_
!= NULL
)
364 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
367 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
368 out
<< "for" << ' ' << "each" << ' ' << '(';
369 initialiser_
->ForIn(out
, CYNoIn
);
370 out
<< ' ' << "in" << ' ' << *set_
<< ')';
371 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
374 void CYForOfComprehension::Output(CYOutput
&out
) const {
375 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
378 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
379 out
<< "for" << ' ' << '(';
380 if (initialiser_
!= NULL
)
381 initialiser_
->ForIn(out
, CYNoIn
);
382 out
<< ' ' << "in" << ' ' << *set_
<< ')';
383 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
386 void CYForInComprehension::Output(CYOutput
&out
) const {
387 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
390 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
391 // XXX: one could imagine using + here to save a byte
392 bool protect((flags
& CYNoFunction
) != 0);
397 out
<< ' ' << *name_
;
398 out
<< '(' << parameters_
<< ')' << ' ';
408 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
409 CYFunction::Output(out
, flags
);
412 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
413 CYFunction::Output(out
, flags
);
416 void CYFunctionParameter::Output(CYOutput
&out
) const {
417 initialiser_
->Output(out
, CYNoFlags
);
419 out
<< ',' << ' ' << *next_
;
422 const char *CYIdentifier::Word() const {
423 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
426 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
428 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
433 out
<< "if" << ' ' << '(' << *test_
<< ')';
435 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
437 CYFlags
jacks(CYNoDangle
);
441 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
443 unsigned line(out
.position_
.line
);
444 unsigned indent(out
.indent_
);
445 true_
->Single(out
, jacks
, CYCompactShort
);
447 if (false_
!= NULL
) {
448 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
454 false_
->Single(out
, right
, CYCompactLong
);
461 void CYIfComprehension::Output(CYOutput
&out
) const {
462 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
465 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
469 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
470 object_
->Output(out
, Precedence(), CYLeft(flags
));
471 if (const char *word
= property_
->Word())
474 out
<< "->" << '[' << *property_
<< ']';
477 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
478 const char *name(Operator());
479 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
482 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
483 lhs_
->Output(out
, Precedence(), left
);
484 out
<< ' ' << name
<< ' ';
485 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
486 rhs_
->Output(out
, Precedence() - 1, right
);
491 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
492 out
<< *name_
<< ':';
493 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
496 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
498 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
502 void CYStatement::Output(CYOutput
&out
) const {
506 void CYTemplate::Output(CYOutput
&out
, CYFlags flags
) const {
510 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
511 next_
->Output(out
, Precedence(), identifier
);
517 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
519 next_
->Output(out
, Precedence(), identifier
);
520 out
<< ')' << '(' << parameters_
<< ')';
523 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
524 out
<< "const" << ' ';
525 next_
->Output(out
, Precedence(), identifier
);
528 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
529 next_
->Output(out
, Precedence(), identifier
);
530 out
<< '(' << parameters_
<< ')';
533 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
535 next_
->Output(out
, Precedence(), identifier
);
538 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
540 next_
->Output(out
, Precedence(), identifier
);
543 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
549 bool protect(precedence
> Precedence());
553 Output(out
, identifier
);
558 void CYTypedIdentifier::Output(CYOutput
&out
) const {
559 specifier_
->Output(out
);
560 modifier_
->Output(out
, 0, identifier_
);
563 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
564 out
<< "@encode(" << typed_
<< ")";
567 void CYTypedParameter::Output(CYOutput
&out
) const {
570 out
<< ',' << ' ' << next_
;
573 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
574 // XXX: this is seriously wrong
581 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
582 out
<< "typedef" << ' ' << *typed_
;
585 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
586 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
587 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
590 void CYModule::Output(CYOutput
&out
) const {
599 void New::Output(CYOutput
&out
, CYFlags flags
) const {
601 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
602 constructor_
->Output(out
, Precedence(), jacks
);
603 if (arguments_
!= NULL
)
604 out
<< '(' << *arguments_
<< ')';
609 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
613 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
614 std::ostringstream str
;
615 CYNumerify(str
, Value());
616 std::string
value(str
.str());
617 out
<< value
.c_str();
618 // XXX: this should probably also handle hex conversions and exponents
619 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
623 void CYNumber::PropertyName(CYOutput
&out
) const {
624 Output(out
, CYNoFlags
);
627 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
628 bool protect((flags
& CYNoBrace
) != 0);
640 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
641 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
645 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
646 const char *name(Operator());
650 rhs_
->Output(out
, Precedence(), CYRight(flags
));
653 void CYScript::Output(CYOutput
&out
) const {
657 void CYProperty::Output(CYOutput
&out
) const {
659 name_
->PropertyName(out
);
661 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
663 out
<< ',' << '\n' << *next_
;
668 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
672 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
675 out
<< ' ' << *value_
;
679 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
680 call_
->Output(out
, CYLeft(flags
));
682 proc_
->Output(out
, CYRight(flags
));
685 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
686 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
693 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
695 CYForEach (next
, this) {
696 bool last(next
->next_
== NULL
);
697 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
700 next
->Output(out
, jacks
);
705 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
707 return out
.Terminate();
709 _assert(next_
== NULL
);
711 CYCompactType
compact(Compact());
713 if (compact
>= request
)
723 if (compact
< request
)
727 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
728 std::ostringstream str
;
729 CYStringify(str
, value_
, size_
);
730 out
<< str
.str().c_str();
733 void CYString::PropertyName(CYOutput
&out
) const {
734 if (const char *word
= Word())
740 static const char *Reserved_
[] = {
741 "false", "null", "true",
743 "break", "case", "catch", "continue", "default",
744 "delete", "do", "else", "finally", "for", "function",
745 "if", "in", "instanceof", "new", "return", "switch",
746 "this", "throw", "try", "typeof", "var", "void",
751 "class", "enum", "export", "extends", "import", "super",
753 "abstract", "boolean", "byte", "char", "double", "final",
754 "float", "goto", "int", "long", "native", "short",
755 "synchronized", "throws", "transient", "volatile",
762 const char *CYString::Word() const {
763 if (size_
== 0 || !WordStartRange_
[value_
[0]])
765 for (size_t i(1); i
!= size_
; ++i
)
766 if (!WordEndRange_
[value_
[i
]])
768 const char *value(Value());
769 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
770 if (strcmp(*reserved
, value
) == 0)
775 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
776 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
783 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
790 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
793 out
<< ' ' << *value_
;
797 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
804 out
<< catch_
<< finally_
;
809 void CYTypeError::Output(CYOutput
&out
) const {
813 void CYTypeLong::Output(CYOutput
&out
) const {
814 out
<< "long" << specifier_
;
817 void CYTypeShort::Output(CYOutput
&out
) const {
818 out
<< "short" << specifier_
;
821 void CYTypeSigned::Output(CYOutput
&out
) const {
822 out
<< "signed" << specifier_
;
825 void CYTypeUnsigned::Output(CYOutput
&out
) const {
826 out
<< "unsigned" << specifier_
;
829 void CYTypeVariable::Output(CYOutput
&out
) const {
833 void CYTypeVoid::Output(CYOutput
&out
) const {
837 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
839 declarations_
->Output(out
, flags
);
843 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
847 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
848 out
<< "while" << ' ' << '(' << *test_
<< ')';
849 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
852 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
853 out
<< "with" << ' ' << '(' << *scope_
<< ')';
854 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
857 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
859 out
<< "objc_getClass(";
860 out
<< '"' << Word() << '"';
865 void CYWord::Output(CYOutput
&out
) const {
867 if (out
.options_
.verbose_
) {
870 sprintf(number
, "%p", this);
875 void CYWord::PropertyName(CYOutput
&out
) const {
879 const char *CYWord::Word() const {