]>
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" << ' ' << *value_
;
267 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
268 out
<< "debugger" << ';';
271 void CYBinding::Output(CYOutput
&out
, CYFlags flags
) const {
273 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
274 if (initializer_
!= NULL
) {
275 out
<< ' ' << '=' << ' ';
276 initializer_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
280 void CYBindings::Output(CYOutput
&out
) const {
281 Output(out
, CYNoFlags
);
284 void CYBindings::Output(CYOutput
&out
, CYFlags flags
) const {
285 const CYBindings
*binding(this);
289 CYBindings
*next(binding
->next_
);
291 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
293 binding
->binding_
->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 (initializer_
!= NULL
)
386 initializer_
->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 binding_
->Output(out
, CYRight(flags
));
404 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
405 out
<< "for" << ' ' << '(';
406 initializer_
->Output(out
, CYNoIn
| CYNoRightHand
);
407 out
<< ' ' << "in" << ' ' << *iterable_
<< ')';
408 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
411 void CYForInitialized::Output(CYOutput
&out
, CYFlags flags
) const {
412 out
<< "for" << ' ' << '(' << "var" << ' ';
413 binding_
->Output(out
, CYNoIn
| CYNoRightHand
);
414 out
<< ' ' << "in" << ' ' << *iterable_
<< ')';
415 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
418 void CYForInComprehension::Output(CYOutput
&out
) const {
419 out
<< "for" << ' ' << '(';
420 binding_
->Output(out
, CYNoIn
| CYNoRightHand
);
421 out
<< ' ' << "in" << ' ' << *iterable_
<< ')';
424 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
425 out
<< "for" << ' ' << '(';
426 initializer_
->Output(out
, CYNoRightHand
);
427 out
<< ' ' << "of" << ' ' << *iterable_
<< ')';
428 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
431 void CYForOfComprehension::Output(CYOutput
&out
) const {
432 out
<< "for" << ' ' << '(';
433 binding_
->Output(out
, CYNoRightHand
);
434 out
<< ' ' << "of" << ' ' << *iterable_
<< ')' << next_
;
437 void CYForVariable::Output(CYOutput
&out
, CYFlags flags
) const {
439 binding_
->Output(out
, CYRight(flags
));
442 void CYFunction::Output(CYOutput
&out
) const {
443 out
<< '(' << parameters_
<< ')' << ' ';
451 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
452 // XXX: one could imagine using + here to save a byte
453 bool protect((flags
& CYNoFunction
) != 0);
458 out
<< ' ' << *name_
;
459 CYFunction::Output(out
);
464 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
465 out
<< "function" << ' ' << *name_
;
466 CYFunction::Output(out
);
469 void CYFunctionParameter::Output(CYOutput
&out
) const {
470 binding_
->Output(out
, CYNoFlags
);
472 out
<< ',' << ' ' << *next_
;
475 const char *CYIdentifier::Word() const {
476 return next_
== NULL
|| next_
== this ? CYWord::Word() : next_
->Word();
479 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
481 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
486 out
<< "if" << ' ' << '(' << *test_
<< ')';
488 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
490 CYFlags
jacks(CYNoDangle
);
494 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
496 unsigned line(out
.position_
.line
);
497 unsigned indent(out
.indent_
);
498 true_
->Single(out
, jacks
, CYCompactShort
);
500 if (false_
!= NULL
) {
501 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
507 false_
->Single(out
, right
, CYCompactLong
);
514 void CYIfComprehension::Output(CYOutput
&out
) const {
515 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
518 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
522 void CYIndirect::Output(CYOutput
&out
, CYFlags flags
) const {
524 rhs_
->Output(out
, Precedence(), CYRight(flags
));
527 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
528 object_
->Output(out
, Precedence(), CYLeft(flags
));
529 if (const char *word
= property_
->Word())
532 out
<< "->" << '[' << *property_
<< ']';
535 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
536 const char *name(Operator());
537 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
540 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
541 lhs_
->Output(out
, Precedence(), left
);
542 out
<< ' ' << name
<< ' ';
543 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
544 rhs_
->Output(out
, Precedence() - 1, right
);
549 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
550 out
<< *name_
<< ':';
551 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
554 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
556 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
560 void CYStatement::Output(CYOutput
&out
) const {
564 void CYTemplate::Output(CYOutput
&out
, CYFlags flags
) const {
568 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
569 next_
->Output(out
, Precedence(), identifier
);
575 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
577 next_
->Output(out
, Precedence(), identifier
);
578 out
<< ')' << '(' << parameters_
<< ')';
581 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
582 out
<< "const" << ' ';
583 next_
->Output(out
, Precedence(), identifier
);
586 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
587 next_
->Output(out
, Precedence(), identifier
);
588 out
<< '(' << parameters_
<< ')';
591 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
593 next_
->Output(out
, Precedence(), identifier
);
596 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
598 next_
->Output(out
, Precedence(), identifier
);
601 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
607 bool protect(precedence
> Precedence());
611 Output(out
, identifier
);
616 void CYTypedIdentifier::Output(CYOutput
&out
) const {
617 specifier_
->Output(out
);
618 modifier_
->Output(out
, 0, identifier_
);
621 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
622 out
<< "@encode(" << typed_
<< ")";
625 void CYTypedParameter::Output(CYOutput
&out
) const {
628 out
<< ',' << ' ' << next_
;
631 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
632 // XXX: this is seriously wrong
639 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
640 out
<< "typedef" << ' ' << *typed_
;
643 void CYTypeExpression::Output(CYOutput
&out
, CYFlags flags
) const {
644 out
<< '(' << "typedef" << ' ' << *typed_
<< ')';
647 void CYLexical::Output(CYOutput
&out
, CYFlags flags
) const {
649 bindings_
->Output(out
, flags
); // XXX: flags
653 void CYModule::Output(CYOutput
&out
) const {
662 void New::Output(CYOutput
&out
, CYFlags flags
) const {
664 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
665 constructor_
->Output(out
, Precedence(), jacks
);
666 if (arguments_
!= NULL
)
667 out
<< '(' << *arguments_
<< ')';
672 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
676 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
677 std::ostringstream str
;
678 CYNumerify(str
, Value());
679 std::string
value(str
.str());
680 out
<< value
.c_str();
681 // XXX: this should probably also handle hex conversions and exponents
682 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
686 void CYNumber::PropertyName(CYOutput
&out
) const {
687 Output(out
, CYNoFlags
);
690 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
691 bool protect((flags
& CYNoBrace
) != 0);
703 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
704 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
708 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
709 const char *name(Operator());
713 rhs_
->Output(out
, Precedence(), CYRight(flags
));
716 void CYScript::Output(CYOutput
&out
) const {
720 void CYProperty::Output(CYOutput
&out
) const {
721 if (next_
!= NULL
|| out
.pretty_
)
723 out
<< '\n' << next_
;
726 void CYPropertyGetter::Output(CYOutput
&out
) const {
728 name_
->PropertyName(out
);
729 CYFunction::Output(out
);
730 CYProperty::Output(out
);
733 void CYPropertyMethod::Output(CYOutput
&out
) const {
734 name_
->PropertyName(out
);
735 CYFunction::Output(out
);
736 CYProperty::Output(out
);
739 void CYPropertySetter::Output(CYOutput
&out
) const {
741 name_
->PropertyName(out
);
742 CYFunction::Output(out
);
743 CYProperty::Output(out
);
746 void CYPropertyValue::Output(CYOutput
&out
) const {
748 name_
->PropertyName(out
);
750 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
751 CYProperty::Output(out
);
754 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
758 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
761 out
<< ' ' << *value_
;
765 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
766 call_
->Output(out
, CYLeft(flags
));
768 proc_
->Output(out
, CYRight(flags
));
771 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
772 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
779 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
781 CYForEach (next
, this) {
782 bool last(next
->next_
== NULL
);
783 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
786 next
->Output(out
, jacks
);
791 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
793 return out
.Terminate();
795 _assert(next_
== NULL
);
797 CYCompactType
compact(Compact());
799 if (compact
>= request
)
809 if (compact
< request
)
813 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
814 std::ostringstream str
;
815 CYStringify(str
, value_
, size_
);
816 out
<< str
.str().c_str();
819 void CYString::PropertyName(CYOutput
&out
) const {
820 if (const char *word
= Word())
826 static const char *Reserved_
[] = {
827 "false", "null", "true",
829 "break", "case", "catch", "continue", "default",
830 "delete", "do", "else", "finally", "for", "function",
831 "if", "in", "instanceof", "new", "return", "switch",
832 "this", "throw", "try", "typeof", "var", "void",
837 "class", "enum", "export", "extends", "import", "super",
839 "abstract", "boolean", "byte", "char", "double", "final",
840 "float", "goto", "int", "long", "native", "short",
841 "synchronized", "throws", "transient", "volatile",
848 const char *CYString::Word() const {
849 if (size_
== 0 || !WordStartRange_
[value_
[0]])
851 for (size_t i(1); i
!= size_
; ++i
)
852 if (!WordEndRange_
[value_
[i
]])
854 const char *value(Value());
855 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
856 if (strcmp(*reserved
, value
) == 0)
861 void CYSuperAccess::Output(CYOutput
&out
, CYFlags flags
) const {
863 if (const char *word
= property_
->Word())
866 out
<< '[' << *property_
<< ']';
869 void CYSuperCall::Output(CYOutput
&out
, CYFlags flags
) const {
870 out
<< "super" << '(' << arguments_
<< ')';
873 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
874 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
881 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
888 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
891 out
<< ' ' << *value_
;
895 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
902 out
<< catch_
<< finally_
;
907 void CYTypeError::Output(CYOutput
&out
) const {
911 void CYTypeLong::Output(CYOutput
&out
) const {
912 out
<< "long" << specifier_
;
915 void CYTypeShort::Output(CYOutput
&out
) const {
916 out
<< "short" << specifier_
;
919 void CYTypeSigned::Output(CYOutput
&out
) const {
920 out
<< "signed" << specifier_
;
923 void CYTypeStruct::Output(CYOutput
&out
) const {
924 out
<< "struct" << ' ';
926 out
<< *name_
<< ' ';
929 CYForEach (field
, fields_
) {
930 out
<< '\t' << *field
->typed_
;
938 void CYTypeUnsigned::Output(CYOutput
&out
) const {
939 out
<< "unsigned" << specifier_
;
942 void CYTypeVariable::Output(CYOutput
&out
) const {
946 void CYTypeVoid::Output(CYOutput
&out
) const {
950 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
952 bindings_
->Output(out
, flags
); // XXX: flags
956 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
960 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
961 out
<< "while" << ' ' << '(' << *test_
<< ')';
962 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
965 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
966 out
<< "with" << ' ' << '(' << *scope_
<< ')';
967 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
970 void CYWord::Output(CYOutput
&out
) const {
972 if (out
.options_
.verbose_
) {
975 sprintf(number
, "%p", this);
980 void CYWord::PropertyName(CYOutput
&out
) const {
984 const char *CYWord::Word() const {