]>
git.saurik.com Git - cycript.git/blob - Output.cpp
4506db614accb9be3ce02887db811e9ddf8dd4c8
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"
28 void CYOutput::Terminate() {
33 CYOutput
&CYOutput::operator <<(char rhs
) {
34 if (rhs
== ' ' || rhs
== '\n')
40 for (unsigned i(0); i
!= indent_
; ++i
)
43 else if (rhs
== '\r') {
55 if (mode_
== Terminated
&& rhs
!= '}') {
67 } else if (rhs
== '+') {
71 } else if (rhs
== '-') {
72 if (mode_
== NoHyphen
)
75 } else if (WordEndRange_
[rhs
]) {
76 if (mode_
== NoLetter
)
88 CYOutput
&CYOutput::operator <<(const char *rhs
) {
89 size_t size(strlen(rhs
));
94 if (mode_
== Terminated
)
97 mode_
== NoPlus
&& *rhs
== '+' ||
98 mode_
== NoHyphen
&& *rhs
== '-' ||
99 mode_
== NoLetter
&& WordEndRange_
[*rhs
]
103 char last(rhs
[size
- 1]);
104 if (WordEndRange_
[last
] || last
== '/')
110 operator ()(rhs
, size
);
114 void CYArgument::Output(CYOutput
&out
) const {
121 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
124 out
<< ' ' << *next_
;
128 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
129 out
<< '[' << elements_
<< ']';
132 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
133 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
136 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
137 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
138 out
<< ' ' << Operator() << ' ';
139 rhs_
->Output(out
, Precedence(), CYRight(flags
));
142 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
150 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
151 out
<< '!' << (Value() ? "0" : "1");
152 if ((flags
& CYNoInteger
) != 0)
156 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
159 out
<< ' ' << *label_
;
163 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
164 bool protect((flags
& CYNoCall
) != 0);
167 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
168 out
<< '(' << arguments_
<< ')';
176 void Catch::Output(CYOutput
&out
) const {
177 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ';
187 void CYClassExpression::Output(CYOutput
&out
, CYFlags flags
) const {
188 bool protect((flags
& CYNoClass
) != 0);
193 out
<< ' ' << *name_
;
199 void CYClassStatement::Output(CYOutput
&out
, CYFlags flags
) const {
200 out
<< "class" << ' ' << *name_
<< *tail_
;
203 void CYClassTail::Output(CYOutput
&out
) const {
204 if (extends_
== NULL
)
209 out
<< "extends" << ' ';
210 extends_
->Output(out
, CYAssign::Precedence_
- 1, CYNoFlags
);
222 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
224 expression_
->Output(out
, flags
);
226 expression_
->Output(out
, CYLeft(flags
));
228 next_
->Output(out
, CYRight(flags
));
232 void CYComputed::PropertyName(CYOutput
&out
) const {
234 expression_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
238 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
239 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
240 out
<< ' ' << '?' << ' ';
242 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
243 out
<< ' ' << ':' << ' ';
244 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
247 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
250 out
<< ' ' << *label_
;
254 void CYClause::Output(CYOutput
&out
) const {
257 out
<< "case" << ' ' << *case_
;
267 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
268 out
<< "debugger" << ';';
271 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
273 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
274 if (initialiser_
!= NULL
) {
275 out
<< ' ' << '=' << ' ';
276 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
280 void CYDeclarations::Output(CYOutput
&out
) const {
281 Output(out
, CYNoFlags
);
284 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
285 const CYDeclarations
*declaration(this);
289 CYDeclarations
*next(declaration
->next_
);
291 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
293 declaration
->declaration_
->Output(out
, jacks
);
303 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
304 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
305 if (const char *word
= property_
->Word())
308 out
<< '[' << *property_
<< ']';
311 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
314 unsigned line(out
.position_
.line
);
315 unsigned indent(out
.indent_
);
316 code_
->Single(out
, CYCenter(flags
), CYCompactLong
);
318 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
323 out
<< "while" << ' ' << '(' << *test_
<< ')';
326 void CYElementSpread::Output(CYOutput
&out
) const {
327 out
<< "..." << value_
;
330 void CYElementValue::Output(CYOutput
&out
) const {
332 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
333 if (next_
!= NULL
|| value_
== NULL
) {
335 if (next_
!= NULL
&& !next_
->Elision())
342 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
346 void CYEval::Output(CYOutput
&out
, CYFlags flags
) const {
350 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
351 expression_
->Output(out
, flags
| CYNoBFC
);
355 void CYExpression::Output(CYOutput
&out
) const {
356 Output(out
, CYNoFlags
);
359 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
360 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
361 out
<< '(' << *this << ')';
366 void CYExternal::Output(CYOutput
&out
, CYFlags flags
) const {
367 out
<< "extern" << abi_
<< typed_
<< ';';
370 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
371 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << '{' << code_
<< '}';
374 void CYFinally::Output(CYOutput
&out
) const {
375 out
<< ' ' << "finally" << ' ';
383 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
384 out
<< "for" << ' ' << '(';
385 if (initialiser_
!= NULL
)
386 initialiser_
->Output(out
, CYNoIn
);
392 if (increment_
!= NULL
)
396 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
399 void CYForLexical::Output(CYOutput
&out
, CYFlags flags
) const {
400 out
<< (constant_
? "const" : "let") << ' ';
401 declaration_
->Output(out
, CYRight(flags
));
404 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
405 out
<< "for" << ' ' << '(';
406 initialiser_
->Output(out
, CYNoIn
| CYNoRightHand
);
407 out
<< ' ' << "in" << ' ' << *set_
<< ')';
408 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
411 void CYForInComprehension::Output(CYOutput
&out
) const {
412 out
<< "for" << ' ' << '(';
413 declaration_
->Output(out
, CYNoIn
| CYNoRightHand
);
414 out
<< ' ' << "in" << ' ' << *set_
<< ')';
417 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
418 out
<< "for" << ' ' << '(';
419 initialiser_
->Output(out
, CYNoRightHand
);
420 out
<< ' ' << "of" << ' ' << *set_
<< ')';
421 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
424 void CYForOfComprehension::Output(CYOutput
&out
) const {
425 out
<< "for" << ' ' << '(';
426 declaration_
->Output(out
, CYNoRightHand
);
427 out
<< ' ' << "of" << ' ' << *set_
<< ')' << next_
;
430 void CYForVariable::Output(CYOutput
&out
, CYFlags flags
) const {
432 declaration_
->Output(out
, CYRight(flags
));
435 void CYFunction::Output(CYOutput
&out
) const {
436 out
<< '(' << parameters_
<< ')' << ' ';
444 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
445 // XXX: one could imagine using + here to save a byte
446 bool protect((flags
& CYNoFunction
) != 0);
451 out
<< ' ' << *name_
;
452 CYFunction::Output(out
);
457 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
458 out
<< "function" << ' ' << *name_
;
459 CYFunction::Output(out
);
462 void CYFunctionParameter::Output(CYOutput
&out
) const {
463 initialiser_
->Output(out
, CYNoFlags
);
465 out
<< ',' << ' ' << *next_
;
468 const char *CYIdentifier::Word() const {
469 return next_
== NULL
|| next_
== this ? CYWord::Word() : next_
->Word();
472 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
474 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
479 out
<< "if" << ' ' << '(' << *test_
<< ')';
481 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
483 CYFlags
jacks(CYNoDangle
);
487 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
489 unsigned line(out
.position_
.line
);
490 unsigned indent(out
.indent_
);
491 true_
->Single(out
, jacks
, CYCompactShort
);
493 if (false_
!= NULL
) {
494 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
500 false_
->Single(out
, right
, CYCompactLong
);
507 void CYIfComprehension::Output(CYOutput
&out
) const {
508 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
511 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
515 void CYIndirect::Output(CYOutput
&out
, CYFlags flags
) const {
517 rhs_
->Output(out
, Precedence(), CYRight(flags
));
520 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
521 object_
->Output(out
, Precedence(), CYLeft(flags
));
522 if (const char *word
= property_
->Word())
525 out
<< "->" << '[' << *property_
<< ']';
528 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
529 const char *name(Operator());
530 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
533 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
534 lhs_
->Output(out
, Precedence(), left
);
535 out
<< ' ' << name
<< ' ';
536 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
537 rhs_
->Output(out
, Precedence() - 1, right
);
542 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
543 out
<< *name_
<< ':';
544 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
547 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
549 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
553 void CYStatement::Output(CYOutput
&out
) const {
557 void CYTemplate::Output(CYOutput
&out
, CYFlags flags
) const {
561 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
562 next_
->Output(out
, Precedence(), identifier
);
568 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
570 next_
->Output(out
, Precedence(), identifier
);
571 out
<< ')' << '(' << parameters_
<< ')';
574 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
575 out
<< "const" << ' ';
576 next_
->Output(out
, Precedence(), identifier
);
579 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
580 next_
->Output(out
, Precedence(), identifier
);
581 out
<< '(' << parameters_
<< ')';
584 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
586 next_
->Output(out
, Precedence(), identifier
);
589 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
591 next_
->Output(out
, Precedence(), identifier
);
594 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
600 bool protect(precedence
> Precedence());
604 Output(out
, identifier
);
609 void CYTypedIdentifier::Output(CYOutput
&out
) const {
610 specifier_
->Output(out
);
611 modifier_
->Output(out
, 0, identifier_
);
614 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
615 out
<< "@encode(" << typed_
<< ")";
618 void CYTypedParameter::Output(CYOutput
&out
) const {
621 out
<< ',' << ' ' << next_
;
624 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
625 // XXX: this is seriously wrong
632 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
633 out
<< "typedef" << ' ' << *typed_
;
636 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
638 declarations_
->Output(out
, flags
); // XXX: flags
642 void CYModule::Output(CYOutput
&out
) const {
651 void New::Output(CYOutput
&out
, CYFlags flags
) const {
653 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
654 constructor_
->Output(out
, Precedence(), jacks
);
655 if (arguments_
!= NULL
)
656 out
<< '(' << *arguments_
<< ')';
661 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
665 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
666 std::ostringstream str
;
667 CYNumerify(str
, Value());
668 std::string
value(str
.str());
669 out
<< value
.c_str();
670 // XXX: this should probably also handle hex conversions and exponents
671 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
675 void CYNumber::PropertyName(CYOutput
&out
) const {
676 Output(out
, CYNoFlags
);
679 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
680 bool protect((flags
& CYNoBrace
) != 0);
692 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
693 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
697 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
698 const char *name(Operator());
702 rhs_
->Output(out
, Precedence(), CYRight(flags
));
705 void CYScript::Output(CYOutput
&out
) const {
709 void CYProperty::Output(CYOutput
&out
) const {
710 if (next_
!= NULL
|| out
.pretty_
)
712 out
<< '\n' << next_
;
715 void CYPropertyGetter::Output(CYOutput
&out
) const {
717 name_
->PropertyName(out
);
718 CYFunction::Output(out
);
719 CYProperty::Output(out
);
722 void CYPropertyMethod::Output(CYOutput
&out
) const {
723 name_
->PropertyName(out
);
724 CYFunction::Output(out
);
725 CYProperty::Output(out
);
728 void CYPropertySetter::Output(CYOutput
&out
) const {
730 name_
->PropertyName(out
);
731 CYFunction::Output(out
);
732 CYProperty::Output(out
);
735 void CYPropertyValue::Output(CYOutput
&out
) const {
737 name_
->PropertyName(out
);
739 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
740 CYProperty::Output(out
);
743 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
747 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
750 out
<< ' ' << *value_
;
754 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
755 call_
->Output(out
, CYLeft(flags
));
757 proc_
->Output(out
, CYRight(flags
));
760 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
761 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
768 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
770 CYForEach (next
, this) {
771 bool last(next
->next_
== NULL
);
772 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
775 next
->Output(out
, jacks
);
780 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
782 return out
.Terminate();
784 _assert(next_
== NULL
);
786 CYCompactType
compact(Compact());
788 if (compact
>= request
)
798 if (compact
< request
)
802 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
803 std::ostringstream str
;
804 CYStringify(str
, value_
, size_
);
805 out
<< str
.str().c_str();
808 void CYString::PropertyName(CYOutput
&out
) const {
809 if (const char *word
= Word())
815 static const char *Reserved_
[] = {
816 "false", "null", "true",
818 "break", "case", "catch", "continue", "default",
819 "delete", "do", "else", "finally", "for", "function",
820 "if", "in", "instanceof", "new", "return", "switch",
821 "this", "throw", "try", "typeof", "var", "void",
826 "class", "enum", "export", "extends", "import", "super",
828 "abstract", "boolean", "byte", "char", "double", "final",
829 "float", "goto", "int", "long", "native", "short",
830 "synchronized", "throws", "transient", "volatile",
837 const char *CYString::Word() const {
838 if (size_
== 0 || !WordStartRange_
[value_
[0]])
840 for (size_t i(1); i
!= size_
; ++i
)
841 if (!WordEndRange_
[value_
[i
]])
843 const char *value(Value());
844 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
845 if (strcmp(*reserved
, value
) == 0)
850 void CYSuperAccess::Output(CYOutput
&out
, CYFlags flags
) const {
852 if (const char *word
= property_
->Word())
855 out
<< '[' << *property_
<< ']';
858 void CYSuperCall::Output(CYOutput
&out
, CYFlags flags
) const {
859 out
<< "super" << '(' << arguments_
<< ')';
862 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
863 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
870 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
877 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
880 out
<< ' ' << *value_
;
884 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
891 out
<< catch_
<< finally_
;
896 void CYTypeError::Output(CYOutput
&out
) const {
900 void CYTypeLong::Output(CYOutput
&out
) const {
901 out
<< "long" << specifier_
;
904 void CYTypeShort::Output(CYOutput
&out
) const {
905 out
<< "short" << specifier_
;
908 void CYTypeSigned::Output(CYOutput
&out
) const {
909 out
<< "signed" << specifier_
;
912 void CYTypeUnsigned::Output(CYOutput
&out
) const {
913 out
<< "unsigned" << specifier_
;
916 void CYTypeVariable::Output(CYOutput
&out
) const {
920 void CYTypeVoid::Output(CYOutput
&out
) const {
924 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
926 declarations_
->Output(out
, flags
); // XXX: flags
930 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
934 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
935 out
<< "while" << ' ' << '(' << *test_
<< ')';
936 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
939 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
940 out
<< "with" << ' ' << '(' << *scope_
<< ')';
941 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
944 void CYWord::Output(CYOutput
&out
) const {
946 if (out
.options_
.verbose_
) {
949 sprintf(number
, "%p", this);
954 void CYWord::PropertyName(CYOutput
&out
) const {
958 const char *CYWord::Word() const {