]>
git.saurik.com Git - cycript.git/blob - Output.cpp
50740050b40694f718ef41322e3770d1456901f6
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 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
, CYFlags flags
) const {
148 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
149 out
<< (Value() ? "true" : "false");
152 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
155 out
<< ' ' << *label_
;
159 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
160 bool protect((flags
& CYNoCall
) != 0);
163 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
164 out
<< '(' << arguments_
<< ')';
172 void Catch::Output(CYOutput
&out
) const {
173 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ';
183 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
190 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
192 expression_
->Output(out
, flags
);
194 expression_
->Output(out
, CYLeft(flags
));
196 next_
->Output(out
, CYRight(flags
));
200 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
201 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
202 out
<< ' ' << '?' << ' ';
204 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
205 out
<< ' ' << ':' << ' ';
206 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
209 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
212 out
<< ' ' << *label_
;
216 void CYClause::Output(CYOutput
&out
) const {
218 out
<< "case" << ' ' << *case_
;
226 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
227 out
<< "debugger" << ';';
230 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
232 Output(out
, CYRight(flags
));
235 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
237 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
238 if (initialiser_
!= NULL
) {
239 out
<< ' ' << '=' << ' ';
240 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
244 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
246 declarations_
->Output(out
, CYRight(flags
));
249 void CYDeclarations::Output(CYOutput
&out
) const {
250 Output(out
, CYNoFlags
);
253 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
254 const CYDeclarations
*declaration(this);
258 CYDeclarations
*next(declaration
->next_
);
260 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
262 declaration
->declaration_
->Output(out
, jacks
);
272 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
273 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
274 if (const char *word
= property_
->Word())
277 out
<< '[' << *property_
<< ']';
280 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
282 code_
->Single(out
, CYCenter(flags
));
283 out
<< "while" << ' ' << '(' << *test_
<< ')';
286 void CYElement::Output(CYOutput
&out
) const {
288 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
289 if (next_
!= NULL
|| value_
== NULL
) {
291 if (next_
!= NULL
&& next_
->value_
!= NULL
)
298 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
302 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
303 expression_
->Output(out
, flags
| CYNoBF
);
307 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
308 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
311 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
312 Output(out
, flags
| CYNoRightHand
);
315 void CYExpression::Output(CYOutput
&out
) const {
316 Output(out
, CYNoFlags
);
319 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
320 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
321 out
<< '(' << *this << ')';
326 void CYExternal::Output(CYOutput
&out
, CYFlags flags
) const {
327 out
<< "extern" << abi_
<< typed_
<< ';';
330 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
331 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << '{' << code_
<< '}';
334 void CYFinally::Output(CYOutput
&out
) const {
335 out
<< ' ' << "finally" << ' ';
343 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
344 out
<< "for" << ' ' << '(';
345 if (initialiser_
!= NULL
)
346 initialiser_
->Output(out
, CYNoIn
);
352 if (increment_
!= NULL
)
356 code_
->Single(out
, CYRight(flags
));
359 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
360 out
<< "for" << ' ' << "each" << ' ' << '(';
361 initialiser_
->ForIn(out
, CYNoIn
);
362 out
<< "in" << *set_
<< ')';
363 code_
->Single(out
, CYRight(flags
));
366 void CYForOfComprehension::Output(CYOutput
&out
) const {
367 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
370 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
371 out
<< "for" << ' ' << '(';
372 if (initialiser_
!= NULL
)
373 initialiser_
->ForIn(out
, CYNoIn
);
374 out
<< "in" << *set_
<< ')';
375 code_
->Single(out
, CYRight(flags
));
378 void CYForInComprehension::Output(CYOutput
&out
) const {
379 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
382 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
383 // XXX: one could imagine using + here to save a byte
384 bool protect((flags
& CYNoFunction
) != 0);
389 out
<< ' ' << *name_
;
390 out
<< '(' << parameters_
<< ')' << ' ';
400 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
401 CYFunction::Output(out
, flags
);
404 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
405 CYFunction::Output(out
, flags
);
408 void CYFunctionParameter::Output(CYOutput
&out
) const {
409 initialiser_
->Output(out
, CYNoFlags
);
411 out
<< ',' << ' ' << *next_
;
414 const char *CYIdentifier::Word() const {
415 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
418 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
420 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
425 out
<< "if" << ' ' << '(' << *test_
<< ')';
427 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
429 CYFlags
jacks(CYNoDangle
);
433 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
435 true_
->Single(out
, jacks
);
437 if (false_
!= NULL
) {
438 out
<< '\t' << "else";
439 false_
->Single(out
, right
);
446 void CYIfComprehension::Output(CYOutput
&out
) const {
447 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
450 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
454 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
455 object_
->Output(out
, Precedence(), CYLeft(flags
));
456 if (const char *word
= property_
->Word())
459 out
<< "->" << '[' << *property_
<< ']';
462 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
463 const char *name(Operator());
464 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
467 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
468 lhs_
->Output(out
, Precedence(), left
);
469 out
<< ' ' << name
<< ' ';
470 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
471 rhs_
->Output(out
, Precedence() - 1, right
);
476 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
477 out
<< *name_
<< ':' << ' ';
478 statement_
->Single(out
, CYRight(flags
));
481 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
483 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
487 void CYStatement::Output(CYOutput
&out
) const {
491 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
492 next_
->Output(out
, Precedence(), identifier
);
498 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
500 next_
->Output(out
, Precedence(), identifier
);
501 out
<< ')' << '(' << parameters_
<< ')';
504 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
506 next_
->Output(out
, Precedence(), identifier
);
509 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
510 next_
->Output(out
, Precedence(), identifier
);
511 out
<< '(' << parameters_
<< ')';
514 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
516 next_
->Output(out
, Precedence(), identifier
);
519 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
521 next_
->Output(out
, Precedence(), identifier
);
524 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
530 bool protect(precedence
> Precedence());
534 Output(out
, identifier
);
539 void CYTypedIdentifier::Output(CYOutput
&out
) const {
540 specifier_
->Output(out
);
541 modifier_
->Output(out
, 0, identifier_
);
544 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
545 out
<< "@encode(" << typed_
<< ")";
548 void CYTypedParameter::Output(CYOutput
&out
) const {
551 out
<< ',' << ' ' << next_
;
554 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
555 // XXX: this is seriously wrong
562 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
563 out
<< "typedef" << *typed_
;
566 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
567 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
568 code_
->Single(out
, CYRight(flags
));
571 void CYModule::Output(CYOutput
&out
) const {
580 void New::Output(CYOutput
&out
, CYFlags flags
) const {
582 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
583 constructor_
->Output(out
, Precedence(), jacks
);
584 if (arguments_
!= NULL
)
585 out
<< '(' << *arguments_
<< ')';
590 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
594 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
595 std::ostringstream str
;
596 CYNumerify(str
, Value());
597 std::string
value(str
.str());
598 out
<< value
.c_str();
599 // XXX: this should probably also handle hex conversions and exponents
600 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
604 void CYNumber::PropertyName(CYOutput
&out
) const {
605 Output(out
, CYNoFlags
);
608 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
609 bool protect((flags
& CYNoBrace
) != 0);
621 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
622 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
626 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
627 const char *name(Operator());
631 rhs_
->Output(out
, Precedence(), CYRight(flags
));
634 void CYProgram::Output(CYOutput
&out
) const {
638 void CYProperty::Output(CYOutput
&out
) const {
640 name_
->PropertyName(out
);
642 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
644 out
<< ',' << '\n' << *next_
;
649 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
653 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
656 out
<< ' ' << *value_
;
660 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
661 call_
->Output(out
, CYLeft(flags
));
663 proc_
->Output(out
, CYRight(flags
));
666 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
667 // XXX: this is not outputting the parameters
675 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
677 CYForEach (next
, this) {
678 bool last(next
->next_
== NULL
);
679 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
682 next
->Output(out
, jacks
);
687 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
689 return out
.Terminate();
691 _assert(next_
== NULL
);
700 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
701 std::ostringstream str
;
702 CYStringify(str
, value_
, size_
);
703 out
<< str
.str().c_str();
706 void CYString::PropertyName(CYOutput
&out
) const {
707 if (const char *word
= Word())
713 static const char *Reserved_
[] = {
714 "false", "null", "true",
716 "break", "case", "catch", "continue", "default",
717 "delete", "do", "else", "finally", "for", "function",
718 "if", "in", "instanceof", "new", "return", "switch",
719 "this", "throw", "try", "typeof", "var", "void",
724 "class", "enum", "export", "extends", "import", "super",
726 "abstract", "boolean", "byte", "char", "double", "final",
727 "float", "goto", "int", "long", "native", "short",
728 "synchronized", "throws", "transient", "volatile",
735 const char *CYString::Word() const {
736 if (size_
== 0 || !WordStartRange_
[value_
[0]])
738 for (size_t i(1); i
!= size_
; ++i
)
739 if (!WordEndRange_
[value_
[i
]])
741 const char *value(Value());
742 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
743 if (strcmp(*reserved
, value
) == 0)
748 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
749 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
754 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
761 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
764 out
<< ' ' << *value_
;
768 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
775 out
<< catch_
<< finally_
;
780 void CYTypeError::Output(CYOutput
&out
) const {
784 void CYTypeLong::Output(CYOutput
&out
) const {
785 out
<< "long" << specifier_
;
788 void CYTypeShort::Output(CYOutput
&out
) const {
789 out
<< "short" << specifier_
;
792 void CYTypeSigned::Output(CYOutput
&out
) const {
793 out
<< "signed" << specifier_
;
796 void CYTypeUnsigned::Output(CYOutput
&out
) const {
797 out
<< "unsigned" << specifier_
;
800 void CYTypeVariable::Output(CYOutput
&out
) const {
804 void CYTypeVoid::Output(CYOutput
&out
) const {
808 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
810 declarations_
->Output(out
, flags
);
814 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
818 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
819 out
<< "while" << '(' << *test_
<< ')';
820 code_
->Single(out
, CYRight(flags
));
823 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
824 out
<< "with" << '(' << *scope_
<< ')';
825 code_
->Single(out
, CYRight(flags
));
828 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
830 out
<< "objc_getClass(";
831 out
<< '"' << Word() << '"';
836 void CYWord::Output(CYOutput
&out
) const {
838 if (out
.options_
.verbose_
)
839 out
.out_
<< '@' << this;
842 void CYWord::PropertyName(CYOutput
&out
) const {
846 const char *CYWord::Word() const {