]>
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::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 CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
401 declarations_
->Output(out
, CYRight(flags
));
404 void CYForLexical::Output(CYOutput
&out
, CYFlags flags
) const {
405 out
<< (constant_
? "const" : "let") << ' ';
406 declaration_
->Output(out
, CYRight(flags
));
409 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
410 out
<< "for" << ' ' << '(';
411 initialiser_
->Output(out
, CYNoIn
| CYNoRightHand
);
412 out
<< ' ' << "in" << ' ' << *set_
<< ')';
413 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
416 void CYForInComprehension::Output(CYOutput
&out
) const {
417 out
<< "for" << ' ' << '(';
418 declaration_
->Output(out
, CYNoIn
| CYNoRightHand
);
419 out
<< ' ' << "in" << ' ' << *set_
<< ')';
422 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
423 out
<< "for" << ' ' << '(';
424 initialiser_
->Output(out
, CYNoRightHand
);
425 out
<< ' ' << "of" << ' ' << *set_
<< ')';
426 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
429 void CYForOfComprehension::Output(CYOutput
&out
) const {
430 out
<< "for" << ' ' << '(';
431 declaration_
->Output(out
, CYNoRightHand
);
432 out
<< ' ' << "of" << ' ' << *set_
<< ')' << next_
;
435 void CYForVariable::Output(CYOutput
&out
, CYFlags flags
) const {
437 declaration_
->Output(out
, CYRight(flags
));
440 void CYFunction::Output(CYOutput
&out
) const {
441 out
<< '(' << parameters_
<< ')' << ' ';
449 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
450 // XXX: one could imagine using + here to save a byte
451 bool protect((flags
& CYNoFunction
) != 0);
456 out
<< ' ' << *name_
;
457 CYFunction::Output(out
);
462 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
463 out
<< "function" << ' ' << *name_
;
464 CYFunction::Output(out
);
467 void CYFunctionParameter::Output(CYOutput
&out
) const {
468 initialiser_
->Output(out
, CYNoFlags
);
470 out
<< ',' << ' ' << *next_
;
473 const char *CYIdentifier::Word() const {
474 return next_
== NULL
|| next_
== this ? CYWord::Word() : next_
->Word();
477 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
479 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
484 out
<< "if" << ' ' << '(' << *test_
<< ')';
486 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
488 CYFlags
jacks(CYNoDangle
);
492 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
494 unsigned line(out
.position_
.line
);
495 unsigned indent(out
.indent_
);
496 true_
->Single(out
, jacks
, CYCompactShort
);
498 if (false_
!= NULL
) {
499 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
505 false_
->Single(out
, right
, CYCompactLong
);
512 void CYIfComprehension::Output(CYOutput
&out
) const {
513 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
516 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
520 void CYIndirect::Output(CYOutput
&out
, CYFlags flags
) const {
522 rhs_
->Output(out
, Precedence(), CYRight(flags
));
525 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
526 object_
->Output(out
, Precedence(), CYLeft(flags
));
527 if (const char *word
= property_
->Word())
530 out
<< "->" << '[' << *property_
<< ']';
533 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
534 const char *name(Operator());
535 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
538 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
539 lhs_
->Output(out
, Precedence(), left
);
540 out
<< ' ' << name
<< ' ';
541 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
542 rhs_
->Output(out
, Precedence() - 1, right
);
547 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
548 out
<< *name_
<< ':';
549 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
552 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
554 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
558 void CYStatement::Output(CYOutput
&out
) const {
562 void CYTemplate::Output(CYOutput
&out
, CYFlags flags
) const {
566 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
567 next_
->Output(out
, Precedence(), identifier
);
573 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
575 next_
->Output(out
, Precedence(), identifier
);
576 out
<< ')' << '(' << parameters_
<< ')';
579 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
580 out
<< "const" << ' ';
581 next_
->Output(out
, Precedence(), identifier
);
584 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
585 next_
->Output(out
, Precedence(), identifier
);
586 out
<< '(' << parameters_
<< ')';
589 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
591 next_
->Output(out
, Precedence(), identifier
);
594 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
596 next_
->Output(out
, Precedence(), identifier
);
599 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
605 bool protect(precedence
> Precedence());
609 Output(out
, identifier
);
614 void CYTypedIdentifier::Output(CYOutput
&out
) const {
615 specifier_
->Output(out
);
616 modifier_
->Output(out
, 0, identifier_
);
619 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
620 out
<< "@encode(" << typed_
<< ")";
623 void CYTypedParameter::Output(CYOutput
&out
) const {
626 out
<< ',' << ' ' << next_
;
629 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
630 // XXX: this is seriously wrong
637 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
638 out
<< "typedef" << ' ' << *typed_
;
641 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
643 declarations_
->Output(out
, flags
); // XXX: flags
647 void CYModule::Output(CYOutput
&out
) const {
656 void New::Output(CYOutput
&out
, CYFlags flags
) const {
658 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
659 constructor_
->Output(out
, Precedence(), jacks
);
660 if (arguments_
!= NULL
)
661 out
<< '(' << *arguments_
<< ')';
666 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
670 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
671 std::ostringstream str
;
672 CYNumerify(str
, Value());
673 std::string
value(str
.str());
674 out
<< value
.c_str();
675 // XXX: this should probably also handle hex conversions and exponents
676 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
680 void CYNumber::PropertyName(CYOutput
&out
) const {
681 Output(out
, CYNoFlags
);
684 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
685 bool protect((flags
& CYNoBrace
) != 0);
697 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
698 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
702 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
703 const char *name(Operator());
707 rhs_
->Output(out
, Precedence(), CYRight(flags
));
710 void CYScript::Output(CYOutput
&out
) const {
714 void CYProperty::Output(CYOutput
&out
) const {
715 if (next_
!= NULL
|| out
.pretty_
)
717 out
<< '\n' << next_
;
720 void CYPropertyGetter::Output(CYOutput
&out
) const {
722 name_
->PropertyName(out
);
723 CYFunction::Output(out
);
724 CYProperty::Output(out
);
727 void CYPropertyMethod::Output(CYOutput
&out
) const {
728 name_
->PropertyName(out
);
729 CYFunction::Output(out
);
730 CYProperty::Output(out
);
733 void CYPropertySetter::Output(CYOutput
&out
) const {
735 name_
->PropertyName(out
);
736 CYFunction::Output(out
);
737 CYProperty::Output(out
);
740 void CYPropertyValue::Output(CYOutput
&out
) const {
742 name_
->PropertyName(out
);
744 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
745 CYProperty::Output(out
);
748 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
752 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
755 out
<< ' ' << *value_
;
759 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
760 call_
->Output(out
, CYLeft(flags
));
762 proc_
->Output(out
, CYRight(flags
));
765 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
766 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
773 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
775 CYForEach (next
, this) {
776 bool last(next
->next_
== NULL
);
777 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
780 next
->Output(out
, jacks
);
785 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
787 return out
.Terminate();
789 _assert(next_
== NULL
);
791 CYCompactType
compact(Compact());
793 if (compact
>= request
)
803 if (compact
< request
)
807 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
808 std::ostringstream str
;
809 CYStringify(str
, value_
, size_
);
810 out
<< str
.str().c_str();
813 void CYString::PropertyName(CYOutput
&out
) const {
814 if (const char *word
= Word())
820 static const char *Reserved_
[] = {
821 "false", "null", "true",
823 "break", "case", "catch", "continue", "default",
824 "delete", "do", "else", "finally", "for", "function",
825 "if", "in", "instanceof", "new", "return", "switch",
826 "this", "throw", "try", "typeof", "var", "void",
831 "class", "enum", "export", "extends", "import", "super",
833 "abstract", "boolean", "byte", "char", "double", "final",
834 "float", "goto", "int", "long", "native", "short",
835 "synchronized", "throws", "transient", "volatile",
842 const char *CYString::Word() const {
843 if (size_
== 0 || !WordStartRange_
[value_
[0]])
845 for (size_t i(1); i
!= size_
; ++i
)
846 if (!WordEndRange_
[value_
[i
]])
848 const char *value(Value());
849 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
850 if (strcmp(*reserved
, value
) == 0)
855 void CYSuperAccess::Output(CYOutput
&out
, CYFlags flags
) const {
857 if (const char *word
= property_
->Word())
860 out
<< '[' << *property_
<< ']';
863 void CYSuperCall::Output(CYOutput
&out
, CYFlags flags
) const {
864 out
<< "super" << '(' << arguments_
<< ')';
867 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
868 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
875 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
882 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
885 out
<< ' ' << *value_
;
889 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
896 out
<< catch_
<< finally_
;
901 void CYTypeError::Output(CYOutput
&out
) const {
905 void CYTypeLong::Output(CYOutput
&out
) const {
906 out
<< "long" << specifier_
;
909 void CYTypeShort::Output(CYOutput
&out
) const {
910 out
<< "short" << specifier_
;
913 void CYTypeSigned::Output(CYOutput
&out
) const {
914 out
<< "signed" << specifier_
;
917 void CYTypeUnsigned::Output(CYOutput
&out
) const {
918 out
<< "unsigned" << specifier_
;
921 void CYTypeVariable::Output(CYOutput
&out
) const {
925 void CYTypeVoid::Output(CYOutput
&out
) const {
929 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
931 declarations_
->Output(out
, flags
); // XXX: flags
935 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
939 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
940 out
<< "while" << ' ' << '(' << *test_
<< ')';
941 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
944 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
945 out
<< "with" << ' ' << '(' << *scope_
<< ')';
946 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
949 void CYWord::Output(CYOutput
&out
) const {
951 if (out
.options_
.verbose_
) {
954 sprintf(number
, "%p", this);
959 void CYWord::PropertyName(CYOutput
&out
) const {
963 const char *CYWord::Word() const {