]>
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 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 CYElementSpread::Output(CYOutput
&out
) const {
295 out
<< "..." << value_
;
298 void CYElementValue::Output(CYOutput
&out
) const {
300 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
301 if (next_
!= NULL
|| value_
== NULL
) {
303 if (next_
!= NULL
&& !next_
->Elision())
310 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
314 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
315 expression_
->Output(out
, flags
| CYNoBF
);
319 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
320 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
323 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
324 Output(out
, flags
| CYNoRightHand
);
327 void CYExpression::Output(CYOutput
&out
) const {
328 Output(out
, CYNoFlags
);
331 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
332 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
333 out
<< '(' << *this << ')';
338 void CYExternal::Output(CYOutput
&out
, CYFlags flags
) const {
339 out
<< "extern" << abi_
<< typed_
<< ';';
342 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
343 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << '{' << code_
<< '}';
346 void CYFinally::Output(CYOutput
&out
) const {
347 out
<< ' ' << "finally" << ' ';
355 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
356 out
<< "for" << ' ' << '(';
357 if (initialiser_
!= NULL
)
358 initialiser_
->Output(out
, CYNoIn
);
364 if (increment_
!= NULL
)
368 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
371 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
372 out
<< "for" << ' ' << "each" << ' ' << '(';
373 initialiser_
->ForIn(out
, CYNoIn
);
374 out
<< ' ' << "in" << ' ' << *set_
<< ')';
375 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
378 void CYForOfComprehension::Output(CYOutput
&out
) const {
379 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
382 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
383 out
<< "for" << ' ' << '(';
384 if (initialiser_
!= NULL
)
385 initialiser_
->ForIn(out
, CYNoIn
);
386 out
<< ' ' << "in" << ' ' << *set_
<< ')';
387 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
390 void CYForInComprehension::Output(CYOutput
&out
) const {
391 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
394 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
395 // XXX: one could imagine using + here to save a byte
396 bool protect((flags
& CYNoFunction
) != 0);
401 out
<< ' ' << *name_
;
402 out
<< '(' << parameters_
<< ')' << ' ';
412 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
413 CYFunction::Output(out
, flags
);
416 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
417 CYFunction::Output(out
, flags
);
420 void CYFunctionParameter::Output(CYOutput
&out
) const {
421 initialiser_
->Output(out
, CYNoFlags
);
423 out
<< ',' << ' ' << *next_
;
426 const char *CYIdentifier::Word() const {
427 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
430 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
432 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
437 out
<< "if" << ' ' << '(' << *test_
<< ')';
439 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
441 CYFlags
jacks(CYNoDangle
);
445 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
447 unsigned line(out
.position_
.line
);
448 unsigned indent(out
.indent_
);
449 true_
->Single(out
, jacks
, CYCompactShort
);
451 if (false_
!= NULL
) {
452 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
458 false_
->Single(out
, right
, CYCompactLong
);
465 void CYIfComprehension::Output(CYOutput
&out
) const {
466 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
469 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
473 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
474 object_
->Output(out
, Precedence(), CYLeft(flags
));
475 if (const char *word
= property_
->Word())
478 out
<< "->" << '[' << *property_
<< ']';
481 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
482 const char *name(Operator());
483 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
486 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
487 lhs_
->Output(out
, Precedence(), left
);
488 out
<< ' ' << name
<< ' ';
489 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
490 rhs_
->Output(out
, Precedence() - 1, right
);
495 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
496 out
<< *name_
<< ':';
497 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
500 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
502 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
506 void CYStatement::Output(CYOutput
&out
) const {
510 void CYTemplate::Output(CYOutput
&out
, CYFlags flags
) const {
514 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
515 next_
->Output(out
, Precedence(), identifier
);
521 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
523 next_
->Output(out
, Precedence(), identifier
);
524 out
<< ')' << '(' << parameters_
<< ')';
527 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
528 out
<< "const" << ' ';
529 next_
->Output(out
, Precedence(), identifier
);
532 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
533 next_
->Output(out
, Precedence(), identifier
);
534 out
<< '(' << parameters_
<< ')';
537 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
539 next_
->Output(out
, Precedence(), identifier
);
542 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
544 next_
->Output(out
, Precedence(), identifier
);
547 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
553 bool protect(precedence
> Precedence());
557 Output(out
, identifier
);
562 void CYTypedIdentifier::Output(CYOutput
&out
) const {
563 specifier_
->Output(out
);
564 modifier_
->Output(out
, 0, identifier_
);
567 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
568 out
<< "@encode(" << typed_
<< ")";
571 void CYTypedParameter::Output(CYOutput
&out
) const {
574 out
<< ',' << ' ' << next_
;
577 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
578 // XXX: this is seriously wrong
585 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
586 out
<< "typedef" << ' ' << *typed_
;
589 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
590 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
591 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
594 void CYModule::Output(CYOutput
&out
) const {
603 void New::Output(CYOutput
&out
, CYFlags flags
) const {
605 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
606 constructor_
->Output(out
, Precedence(), jacks
);
607 if (arguments_
!= NULL
)
608 out
<< '(' << *arguments_
<< ')';
613 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
617 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
618 std::ostringstream str
;
619 CYNumerify(str
, Value());
620 std::string
value(str
.str());
621 out
<< value
.c_str();
622 // XXX: this should probably also handle hex conversions and exponents
623 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
627 void CYNumber::PropertyName(CYOutput
&out
) const {
628 Output(out
, CYNoFlags
);
631 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
632 bool protect((flags
& CYNoBrace
) != 0);
644 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
645 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
649 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
650 const char *name(Operator());
654 rhs_
->Output(out
, Precedence(), CYRight(flags
));
657 void CYScript::Output(CYOutput
&out
) const {
661 void CYProperty::Output(CYOutput
&out
) const {
663 name_
->PropertyName(out
);
665 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
667 out
<< ',' << '\n' << *next_
;
672 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
676 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
679 out
<< ' ' << *value_
;
683 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
684 call_
->Output(out
, CYLeft(flags
));
686 proc_
->Output(out
, CYRight(flags
));
689 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
690 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
697 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
699 CYForEach (next
, this) {
700 bool last(next
->next_
== NULL
);
701 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
704 next
->Output(out
, jacks
);
709 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
711 return out
.Terminate();
713 _assert(next_
== NULL
);
715 CYCompactType
compact(Compact());
717 if (compact
>= request
)
727 if (compact
< request
)
731 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
732 std::ostringstream str
;
733 CYStringify(str
, value_
, size_
);
734 out
<< str
.str().c_str();
737 void CYString::PropertyName(CYOutput
&out
) const {
738 if (const char *word
= Word())
744 static const char *Reserved_
[] = {
745 "false", "null", "true",
747 "break", "case", "catch", "continue", "default",
748 "delete", "do", "else", "finally", "for", "function",
749 "if", "in", "instanceof", "new", "return", "switch",
750 "this", "throw", "try", "typeof", "var", "void",
755 "class", "enum", "export", "extends", "import", "super",
757 "abstract", "boolean", "byte", "char", "double", "final",
758 "float", "goto", "int", "long", "native", "short",
759 "synchronized", "throws", "transient", "volatile",
766 const char *CYString::Word() const {
767 if (size_
== 0 || !WordStartRange_
[value_
[0]])
769 for (size_t i(1); i
!= size_
; ++i
)
770 if (!WordEndRange_
[value_
[i
]])
772 const char *value(Value());
773 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
774 if (strcmp(*reserved
, value
) == 0)
779 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
780 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
787 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
794 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
797 out
<< ' ' << *value_
;
801 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
808 out
<< catch_
<< finally_
;
813 void CYTypeError::Output(CYOutput
&out
) const {
817 void CYTypeLong::Output(CYOutput
&out
) const {
818 out
<< "long" << specifier_
;
821 void CYTypeShort::Output(CYOutput
&out
) const {
822 out
<< "short" << specifier_
;
825 void CYTypeSigned::Output(CYOutput
&out
) const {
826 out
<< "signed" << specifier_
;
829 void CYTypeUnsigned::Output(CYOutput
&out
) const {
830 out
<< "unsigned" << specifier_
;
833 void CYTypeVariable::Output(CYOutput
&out
) const {
837 void CYTypeVoid::Output(CYOutput
&out
) const {
841 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
843 declarations_
->Output(out
, flags
);
847 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
851 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
852 out
<< "while" << ' ' << '(' << *test_
<< ')';
853 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
856 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
857 out
<< "with" << ' ' << '(' << *scope_
<< ')';
858 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
861 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
863 out
<< "objc_getClass(";
864 out
<< '"' << Word() << '"';
869 void CYWord::Output(CYOutput
&out
) const {
871 if (out
.options_
.verbose_
) {
874 sprintf(number
, "%p", this);
879 void CYWord::PropertyName(CYOutput
&out
) const {
883 const char *CYWord::Word() const {