]>
git.saurik.com Git - cycript.git/blob - Output.cpp
d3da0e46fa0564f386acbd333b64451f23bd76ba
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_
;
371 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
372 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << '{' << code_
<< '}';
375 void CYFinally::Output(CYOutput
&out
) const {
376 out
<< ' ' << "finally" << ' ';
384 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
385 out
<< "for" << ' ' << '(';
386 if (initializer_
!= NULL
)
387 initializer_
->Output(out
, CYNoIn
);
393 if (increment_
!= NULL
)
397 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
400 void CYForLexical::Output(CYOutput
&out
, CYFlags flags
) const {
401 out
<< (constant_
? "const" : "let") << ' ';
402 binding_
->Output(out
, CYRight(flags
));
405 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
406 out
<< "for" << ' ' << '(';
407 initializer_
->Output(out
, CYNoIn
| CYNoRightHand
);
408 out
<< ' ' << "in" << ' ' << *iterable_
<< ')';
409 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
412 void CYForInitialized::Output(CYOutput
&out
, CYFlags flags
) const {
413 out
<< "for" << ' ' << '(' << "var" << ' ';
414 binding_
->Output(out
, CYNoIn
| CYNoRightHand
);
415 out
<< ' ' << "in" << ' ' << *iterable_
<< ')';
416 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
419 void CYForInComprehension::Output(CYOutput
&out
) const {
420 out
<< "for" << ' ' << '(';
421 binding_
->Output(out
, CYNoIn
| CYNoRightHand
);
422 out
<< ' ' << "in" << ' ' << *iterable_
<< ')';
425 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
426 out
<< "for" << ' ' << '(';
427 initializer_
->Output(out
, CYNoRightHand
);
428 out
<< ' ' << "of" << ' ' << *iterable_
<< ')';
429 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
432 void CYForOfComprehension::Output(CYOutput
&out
) const {
433 out
<< "for" << ' ' << '(';
434 binding_
->Output(out
, CYNoRightHand
);
435 out
<< ' ' << "of" << ' ' << *iterable_
<< ')' << next_
;
438 void CYForVariable::Output(CYOutput
&out
, CYFlags flags
) const {
440 binding_
->Output(out
, CYRight(flags
));
443 void CYFunction::Output(CYOutput
&out
) const {
444 out
<< '(' << parameters_
<< ')' << ' ';
452 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
453 // XXX: one could imagine using + here to save a byte
454 bool protect((flags
& CYNoFunction
) != 0);
459 out
<< ' ' << *name_
;
460 CYFunction::Output(out
);
465 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
466 out
<< "function" << ' ' << *name_
;
467 CYFunction::Output(out
);
470 void CYFunctionParameter::Output(CYOutput
&out
) const {
471 binding_
->Output(out
, CYNoFlags
);
473 out
<< ',' << ' ' << *next_
;
476 const char *CYIdentifier::Word() const {
477 return next_
== NULL
|| next_
== this ? CYWord::Word() : next_
->Word();
480 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
482 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
487 out
<< "if" << ' ' << '(' << *test_
<< ')';
489 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
491 CYFlags
jacks(CYNoDangle
);
495 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
497 unsigned line(out
.position_
.line
);
498 unsigned indent(out
.indent_
);
499 true_
->Single(out
, jacks
, CYCompactShort
);
501 if (false_
!= NULL
) {
502 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
508 false_
->Single(out
, right
, CYCompactLong
);
515 void CYIfComprehension::Output(CYOutput
&out
) const {
516 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
519 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
523 void CYIndirect::Output(CYOutput
&out
, CYFlags flags
) const {
525 rhs_
->Output(out
, Precedence(), CYRight(flags
));
528 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
529 object_
->Output(out
, Precedence(), CYLeft(flags
));
530 if (const char *word
= property_
->Word())
533 out
<< "->" << '[' << *property_
<< ']';
536 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
537 const char *name(Operator());
538 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
541 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
542 lhs_
->Output(out
, Precedence(), left
);
543 out
<< ' ' << name
<< ' ';
544 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
545 rhs_
->Output(out
, Precedence() - 1, right
);
550 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
551 out
<< *name_
<< ':';
552 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
555 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
557 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
561 void CYStatement::Output(CYOutput
&out
) const {
565 void CYTemplate::Output(CYOutput
&out
, CYFlags flags
) const {
569 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
570 next_
->Output(out
, Precedence(), identifier
);
576 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
578 next_
->Output(out
, Precedence(), identifier
);
579 out
<< ')' << '(' << parameters_
<< ')';
582 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
583 out
<< "const" << ' ';
584 next_
->Output(out
, Precedence(), identifier
);
587 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
588 next_
->Output(out
, Precedence(), identifier
);
589 out
<< '(' << parameters_
<< ')';
592 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
594 next_
->Output(out
, Precedence(), identifier
);
597 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
599 next_
->Output(out
, Precedence(), identifier
);
602 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
608 bool protect(precedence
> Precedence());
612 Output(out
, identifier
);
617 void CYTypedIdentifier::Output(CYOutput
&out
) const {
618 specifier_
->Output(out
);
619 modifier_
->Output(out
, 0, identifier_
);
622 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
623 out
<< "@encode(" << typed_
<< ")";
626 void CYTypedParameter::Output(CYOutput
&out
) const {
629 out
<< ',' << ' ' << next_
;
632 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
633 // XXX: this is seriously wrong
640 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
641 out
<< "typedef" << ' ' << *typed_
;
645 void CYTypeExpression::Output(CYOutput
&out
, CYFlags flags
) const {
646 out
<< '(' << "typedef" << ' ' << *typed_
<< ')';
649 void CYLexical::Output(CYOutput
&out
, CYFlags flags
) const {
651 bindings_
->Output(out
, flags
); // XXX: flags
655 void CYModule::Output(CYOutput
&out
) const {
664 void New::Output(CYOutput
&out
, CYFlags flags
) const {
666 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
667 constructor_
->Output(out
, Precedence(), jacks
);
668 if (arguments_
!= NULL
)
669 out
<< '(' << *arguments_
<< ')';
674 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
678 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
679 std::ostringstream str
;
680 CYNumerify(str
, Value());
681 std::string
value(str
.str());
682 out
<< value
.c_str();
683 // XXX: this should probably also handle hex conversions and exponents
684 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
688 void CYNumber::PropertyName(CYOutput
&out
) const {
689 Output(out
, CYNoFlags
);
692 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
693 bool protect((flags
& CYNoBrace
) != 0);
705 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
706 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
710 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
711 const char *name(Operator());
715 rhs_
->Output(out
, Precedence(), CYRight(flags
));
718 void CYScript::Output(CYOutput
&out
) const {
722 void CYProperty::Output(CYOutput
&out
) const {
723 if (next_
!= NULL
|| out
.pretty_
)
725 out
<< '\n' << next_
;
728 void CYPropertyGetter::Output(CYOutput
&out
) const {
730 name_
->PropertyName(out
);
731 CYFunction::Output(out
);
732 CYProperty::Output(out
);
735 void CYPropertyMethod::Output(CYOutput
&out
) const {
736 name_
->PropertyName(out
);
737 CYFunction::Output(out
);
738 CYProperty::Output(out
);
741 void CYPropertySetter::Output(CYOutput
&out
) const {
743 name_
->PropertyName(out
);
744 CYFunction::Output(out
);
745 CYProperty::Output(out
);
748 void CYPropertyValue::Output(CYOutput
&out
) const {
750 name_
->PropertyName(out
);
752 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
753 CYProperty::Output(out
);
756 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
760 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
763 out
<< ' ' << *value_
;
767 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
768 call_
->Output(out
, CYLeft(flags
));
770 proc_
->Output(out
, CYRight(flags
));
773 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
774 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
781 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
783 CYForEach (next
, this) {
784 bool last(next
->next_
== NULL
);
785 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
788 next
->Output(out
, jacks
);
793 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
795 return out
.Terminate();
797 _assert(next_
== NULL
);
799 CYCompactType
compact(Compact());
801 if (compact
>= request
)
811 if (compact
< request
)
815 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
816 std::ostringstream str
;
817 CYStringify(str
, value_
, size_
);
818 out
<< str
.str().c_str();
821 void CYString::PropertyName(CYOutput
&out
) const {
822 if (const char *word
= Word())
828 static const char *Reserved_
[] = {
829 "false", "null", "true",
831 "break", "case", "catch", "continue", "default",
832 "delete", "do", "else", "finally", "for", "function",
833 "if", "in", "instanceof", "new", "return", "switch",
834 "this", "throw", "try", "typeof", "var", "void",
839 "class", "enum", "export", "extends", "import", "super",
841 "abstract", "boolean", "byte", "char", "double", "final",
842 "float", "goto", "int", "long", "native", "short",
843 "synchronized", "throws", "transient", "volatile",
850 const char *CYString::Word() const {
851 if (size_
== 0 || !WordStartRange_
[value_
[0]])
853 for (size_t i(1); i
!= size_
; ++i
)
854 if (!WordEndRange_
[value_
[i
]])
856 const char *value(Value());
857 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
858 if (strcmp(*reserved
, value
) == 0)
863 void CYSuperAccess::Output(CYOutput
&out
, CYFlags flags
) const {
865 if (const char *word
= property_
->Word())
868 out
<< '[' << *property_
<< ']';
871 void CYSuperCall::Output(CYOutput
&out
, CYFlags flags
) const {
872 out
<< "super" << '(' << arguments_
<< ')';
875 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
876 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
883 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
890 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
893 out
<< ' ' << *value_
;
897 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
904 out
<< catch_
<< finally_
;
909 void CYTypeError::Output(CYOutput
&out
) const {
913 void CYTypeLong::Output(CYOutput
&out
) const {
914 out
<< "long" << specifier_
;
917 void CYTypeShort::Output(CYOutput
&out
) const {
918 out
<< "short" << specifier_
;
921 void CYTypeSigned::Output(CYOutput
&out
) const {
922 out
<< "signed" << specifier_
;
925 void CYTypeStruct::Output(CYOutput
&out
) const {
926 out
<< "struct" << ' ';
928 out
<< *name_
<< ' ';
931 CYForEach (field
, fields_
) {
932 out
<< '\t' << *field
->typed_
;
940 void CYTypeUnsigned::Output(CYOutput
&out
) const {
941 out
<< "unsigned" << specifier_
;
944 void CYTypeVariable::Output(CYOutput
&out
) const {
948 void CYTypeVoid::Output(CYOutput
&out
) const {
952 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
954 bindings_
->Output(out
, flags
); // XXX: flags
958 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
962 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
963 out
<< "while" << ' ' << '(' << *test_
<< ')';
964 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
967 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
968 out
<< "with" << ' ' << '(' << *scope_
<< ')';
969 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
972 void CYWord::Output(CYOutput
&out
) const {
974 if (out
.options_
.verbose_
) {
977 sprintf(number
, "%p", this);
982 void CYWord::PropertyName(CYOutput
&out
) const {
986 const char *CYWord::Word() const {