]>
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"
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::ForIn(CYOutput
&out
, CYFlags flags
) const {
273 Output(out
, CYRight(flags
));
276 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
278 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
279 if (initialiser_
!= NULL
) {
280 out
<< ' ' << '=' << ' ';
281 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
285 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
287 declarations_
->Output(out
, CYRight(flags
));
290 void CYDeclarations::Output(CYOutput
&out
) const {
291 Output(out
, CYNoFlags
);
294 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
295 const CYDeclarations
*declaration(this);
299 CYDeclarations
*next(declaration
->next_
);
301 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
303 declaration
->declaration_
->Output(out
, jacks
);
313 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
314 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
315 if (const char *word
= property_
->Word())
318 out
<< '[' << *property_
<< ']';
321 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
324 unsigned line(out
.position_
.line
);
325 unsigned indent(out
.indent_
);
326 code_
->Single(out
, CYCenter(flags
), CYCompactLong
);
328 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
333 out
<< "while" << ' ' << '(' << *test_
<< ')';
336 void CYElementSpread::Output(CYOutput
&out
) const {
337 out
<< "..." << value_
;
340 void CYElementValue::Output(CYOutput
&out
) const {
342 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
343 if (next_
!= NULL
|| value_
== NULL
) {
345 if (next_
!= NULL
&& !next_
->Elision())
352 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
356 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
357 expression_
->Output(out
, flags
| CYNoBFC
);
361 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
362 Output(out
, flags
| CYNoRightHand
);
365 void CYExpression::Output(CYOutput
&out
) const {
366 Output(out
, CYNoFlags
);
369 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
370 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
371 out
<< '(' << *this << ')';
376 void CYExternal::Output(CYOutput
&out
, CYFlags flags
) const {
377 out
<< "extern" << abi_
<< typed_
<< ';';
380 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
381 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << '{' << code_
<< '}';
384 void CYFinally::Output(CYOutput
&out
) const {
385 out
<< ' ' << "finally" << ' ';
393 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
394 out
<< "for" << ' ' << '(';
395 if (initialiser_
!= NULL
)
396 initialiser_
->Output(out
, CYNoIn
);
402 if (increment_
!= NULL
)
406 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
409 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
410 out
<< "for" << ' ' << "each" << ' ' << '(';
411 initialiser_
->ForIn(out
, CYNoIn
);
412 out
<< ' ' << "in" << ' ' << *set_
<< ')';
413 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
416 void CYForOfComprehension::Output(CYOutput
&out
) const {
417 out
<< "for" << ' ' << "each" << ' ' << '(';
418 declaration_
->Output(out
, CYNoIn
);
419 out
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
422 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
423 out
<< "for" << ' ' << '(';
424 if (initialiser_
!= NULL
)
425 initialiser_
->ForIn(out
, CYNoIn
);
426 out
<< ' ' << "in" << ' ' << *set_
<< ')';
427 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
430 void CYForInComprehension::Output(CYOutput
&out
) const {
431 out
<< "for" << ' ' << '(';
432 declaration_
->Output(out
, CYNoIn
);
433 out
<< ' ' << "in" << ' ' << *set_
<< ')';
436 void CYFunction::Output(CYOutput
&out
) const {
437 out
<< '(' << parameters_
<< ')' << ' ';
445 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
446 // XXX: one could imagine using + here to save a byte
447 bool protect((flags
& CYNoFunction
) != 0);
452 out
<< ' ' << *name_
;
453 CYFunction::Output(out
);
458 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
459 out
<< "function" << ' ' << *name_
;
460 CYFunction::Output(out
);
463 void CYFunctionParameter::Output(CYOutput
&out
) const {
464 initialiser_
->Output(out
, CYNoFlags
);
466 out
<< ',' << ' ' << *next_
;
469 const char *CYIdentifier::Word() const {
470 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
473 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
475 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
480 out
<< "if" << ' ' << '(' << *test_
<< ')';
482 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
484 CYFlags
jacks(CYNoDangle
);
488 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
490 unsigned line(out
.position_
.line
);
491 unsigned indent(out
.indent_
);
492 true_
->Single(out
, jacks
, CYCompactShort
);
494 if (false_
!= NULL
) {
495 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
501 false_
->Single(out
, right
, CYCompactLong
);
508 void CYIfComprehension::Output(CYOutput
&out
) const {
509 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
512 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
516 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
517 object_
->Output(out
, Precedence(), CYLeft(flags
));
518 if (const char *word
= property_
->Word())
521 out
<< "->" << '[' << *property_
<< ']';
524 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
525 const char *name(Operator());
526 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
529 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
530 lhs_
->Output(out
, Precedence(), left
);
531 out
<< ' ' << name
<< ' ';
532 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
533 rhs_
->Output(out
, Precedence() - 1, right
);
538 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
539 out
<< *name_
<< ':';
540 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
543 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
545 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
549 void CYStatement::Output(CYOutput
&out
) const {
553 void CYTemplate::Output(CYOutput
&out
, CYFlags flags
) const {
557 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
558 next_
->Output(out
, Precedence(), identifier
);
564 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
566 next_
->Output(out
, Precedence(), identifier
);
567 out
<< ')' << '(' << parameters_
<< ')';
570 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
571 out
<< "const" << ' ';
572 next_
->Output(out
, Precedence(), identifier
);
575 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
576 next_
->Output(out
, Precedence(), identifier
);
577 out
<< '(' << parameters_
<< ')';
580 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
582 next_
->Output(out
, Precedence(), identifier
);
585 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
587 next_
->Output(out
, Precedence(), identifier
);
590 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
596 bool protect(precedence
> Precedence());
600 Output(out
, identifier
);
605 void CYTypedIdentifier::Output(CYOutput
&out
) const {
606 specifier_
->Output(out
);
607 modifier_
->Output(out
, 0, identifier_
);
610 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
611 out
<< "@encode(" << typed_
<< ")";
614 void CYTypedParameter::Output(CYOutput
&out
) const {
617 out
<< ',' << ' ' << next_
;
620 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
621 // XXX: this is seriously wrong
628 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
629 out
<< "typedef" << ' ' << *typed_
;
632 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
634 declarations_
->Output(out
, flags
); // XXX: flags
638 void CYModule::Output(CYOutput
&out
) const {
647 void New::Output(CYOutput
&out
, CYFlags flags
) const {
649 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
650 constructor_
->Output(out
, Precedence(), jacks
);
651 if (arguments_
!= NULL
)
652 out
<< '(' << *arguments_
<< ')';
657 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
661 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
662 std::ostringstream str
;
663 CYNumerify(str
, Value());
664 std::string
value(str
.str());
665 out
<< value
.c_str();
666 // XXX: this should probably also handle hex conversions and exponents
667 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
671 void CYNumber::PropertyName(CYOutput
&out
) const {
672 Output(out
, CYNoFlags
);
675 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
676 bool protect((flags
& CYNoBrace
) != 0);
688 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
689 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
693 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
694 const char *name(Operator());
698 rhs_
->Output(out
, Precedence(), CYRight(flags
));
701 void CYScript::Output(CYOutput
&out
) const {
705 void CYProperty::Output(CYOutput
&out
) const {
706 if (next_
!= NULL
|| out
.pretty_
)
708 out
<< '\n' << next_
;
711 void CYPropertyGetter::Output(CYOutput
&out
) const {
713 name_
->PropertyName(out
);
714 CYFunction::Output(out
);
715 CYProperty::Output(out
);
718 void CYPropertyMethod::Output(CYOutput
&out
) const {
719 name_
->PropertyName(out
);
720 CYFunction::Output(out
);
721 CYProperty::Output(out
);
724 void CYPropertySetter::Output(CYOutput
&out
) const {
726 name_
->PropertyName(out
);
727 CYFunction::Output(out
);
728 CYProperty::Output(out
);
731 void CYPropertyValue::Output(CYOutput
&out
) const {
733 name_
->PropertyName(out
);
735 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
736 CYProperty::Output(out
);
739 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
743 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
746 out
<< ' ' << *value_
;
750 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
751 call_
->Output(out
, CYLeft(flags
));
753 proc_
->Output(out
, CYRight(flags
));
756 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
757 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
764 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
766 CYForEach (next
, this) {
767 bool last(next
->next_
== NULL
);
768 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
771 next
->Output(out
, jacks
);
776 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
778 return out
.Terminate();
780 _assert(next_
== NULL
);
782 CYCompactType
compact(Compact());
784 if (compact
>= request
)
794 if (compact
< request
)
798 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
799 std::ostringstream str
;
800 CYStringify(str
, value_
, size_
);
801 out
<< str
.str().c_str();
804 void CYString::PropertyName(CYOutput
&out
) const {
805 if (const char *word
= Word())
811 static const char *Reserved_
[] = {
812 "false", "null", "true",
814 "break", "case", "catch", "continue", "default",
815 "delete", "do", "else", "finally", "for", "function",
816 "if", "in", "instanceof", "new", "return", "switch",
817 "this", "throw", "try", "typeof", "var", "void",
822 "class", "enum", "export", "extends", "import", "super",
824 "abstract", "boolean", "byte", "char", "double", "final",
825 "float", "goto", "int", "long", "native", "short",
826 "synchronized", "throws", "transient", "volatile",
833 const char *CYString::Word() const {
834 if (size_
== 0 || !WordStartRange_
[value_
[0]])
836 for (size_t i(1); i
!= size_
; ++i
)
837 if (!WordEndRange_
[value_
[i
]])
839 const char *value(Value());
840 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
841 if (strcmp(*reserved
, value
) == 0)
846 void CYSuperAccess::Output(CYOutput
&out
, CYFlags flags
) const {
848 if (const char *word
= property_
->Word())
851 out
<< '[' << *property_
<< ']';
854 void CYSuperCall::Output(CYOutput
&out
, CYFlags flags
) const {
855 out
<< "super" << '(' << arguments_
<< ')';
858 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
859 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
866 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
873 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
876 out
<< ' ' << *value_
;
880 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
887 out
<< catch_
<< finally_
;
892 void CYTypeError::Output(CYOutput
&out
) const {
896 void CYTypeLong::Output(CYOutput
&out
) const {
897 out
<< "long" << specifier_
;
900 void CYTypeShort::Output(CYOutput
&out
) const {
901 out
<< "short" << specifier_
;
904 void CYTypeSigned::Output(CYOutput
&out
) const {
905 out
<< "signed" << specifier_
;
908 void CYTypeUnsigned::Output(CYOutput
&out
) const {
909 out
<< "unsigned" << specifier_
;
912 void CYTypeVariable::Output(CYOutput
&out
) const {
916 void CYTypeVoid::Output(CYOutput
&out
) const {
920 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
922 declarations_
->Output(out
, flags
); // XXX: flags
926 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
930 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
931 out
<< "while" << ' ' << '(' << *test_
<< ')';
932 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
935 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
936 out
<< "with" << ' ' << '(' << *scope_
<< ')';
937 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
940 void CYWord::Output(CYOutput
&out
) const {
942 if (out
.options_
.verbose_
) {
945 sprintf(number
, "%p", this);
950 void CYWord::PropertyName(CYOutput
&out
) const {
954 const char *CYWord::Word() const {