]>
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 CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
633 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
634 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
637 void CYModule::Output(CYOutput
&out
) const {
646 void New::Output(CYOutput
&out
, CYFlags flags
) const {
648 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
649 constructor_
->Output(out
, Precedence(), jacks
);
650 if (arguments_
!= NULL
)
651 out
<< '(' << *arguments_
<< ')';
656 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
660 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
661 std::ostringstream str
;
662 CYNumerify(str
, Value());
663 std::string
value(str
.str());
664 out
<< value
.c_str();
665 // XXX: this should probably also handle hex conversions and exponents
666 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
670 void CYNumber::PropertyName(CYOutput
&out
) const {
671 Output(out
, CYNoFlags
);
674 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
675 bool protect((flags
& CYNoBrace
) != 0);
687 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
688 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
692 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
693 const char *name(Operator());
697 rhs_
->Output(out
, Precedence(), CYRight(flags
));
700 void CYScript::Output(CYOutput
&out
) const {
704 void CYProperty::Output(CYOutput
&out
) const {
705 if (next_
!= NULL
|| out
.pretty_
)
707 out
<< '\n' << next_
;
710 void CYPropertyGetter::Output(CYOutput
&out
) const {
712 name_
->PropertyName(out
);
713 CYFunction::Output(out
);
714 CYProperty::Output(out
);
717 void CYPropertyMethod::Output(CYOutput
&out
) const {
718 name_
->PropertyName(out
);
719 CYFunction::Output(out
);
720 CYProperty::Output(out
);
723 void CYPropertySetter::Output(CYOutput
&out
) const {
725 name_
->PropertyName(out
);
726 CYFunction::Output(out
);
727 CYProperty::Output(out
);
730 void CYPropertyValue::Output(CYOutput
&out
) const {
732 name_
->PropertyName(out
);
734 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
735 CYProperty::Output(out
);
738 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
742 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
745 out
<< ' ' << *value_
;
749 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
750 call_
->Output(out
, CYLeft(flags
));
752 proc_
->Output(out
, CYRight(flags
));
755 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
756 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
763 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
765 CYForEach (next
, this) {
766 bool last(next
->next_
== NULL
);
767 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
770 next
->Output(out
, jacks
);
775 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
777 return out
.Terminate();
779 _assert(next_
== NULL
);
781 CYCompactType
compact(Compact());
783 if (compact
>= request
)
793 if (compact
< request
)
797 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
798 std::ostringstream str
;
799 CYStringify(str
, value_
, size_
);
800 out
<< str
.str().c_str();
803 void CYString::PropertyName(CYOutput
&out
) const {
804 if (const char *word
= Word())
810 static const char *Reserved_
[] = {
811 "false", "null", "true",
813 "break", "case", "catch", "continue", "default",
814 "delete", "do", "else", "finally", "for", "function",
815 "if", "in", "instanceof", "new", "return", "switch",
816 "this", "throw", "try", "typeof", "var", "void",
821 "class", "enum", "export", "extends", "import", "super",
823 "abstract", "boolean", "byte", "char", "double", "final",
824 "float", "goto", "int", "long", "native", "short",
825 "synchronized", "throws", "transient", "volatile",
832 const char *CYString::Word() const {
833 if (size_
== 0 || !WordStartRange_
[value_
[0]])
835 for (size_t i(1); i
!= size_
; ++i
)
836 if (!WordEndRange_
[value_
[i
]])
838 const char *value(Value());
839 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
840 if (strcmp(*reserved
, value
) == 0)
845 void CYSuperAccess::Output(CYOutput
&out
, CYFlags flags
) const {
847 if (const char *word
= property_
->Word())
850 out
<< '[' << *property_
<< ']';
853 void CYSuperCall::Output(CYOutput
&out
, CYFlags flags
) const {
854 out
<< "super" << '(' << arguments_
<< ')';
857 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
858 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
865 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
872 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
875 out
<< ' ' << *value_
;
879 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
886 out
<< catch_
<< finally_
;
891 void CYTypeError::Output(CYOutput
&out
) const {
895 void CYTypeLong::Output(CYOutput
&out
) const {
896 out
<< "long" << specifier_
;
899 void CYTypeShort::Output(CYOutput
&out
) const {
900 out
<< "short" << specifier_
;
903 void CYTypeSigned::Output(CYOutput
&out
) const {
904 out
<< "signed" << specifier_
;
907 void CYTypeUnsigned::Output(CYOutput
&out
) const {
908 out
<< "unsigned" << specifier_
;
911 void CYTypeVariable::Output(CYOutput
&out
) const {
915 void CYTypeVoid::Output(CYOutput
&out
) const {
919 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
921 declarations_
->Output(out
, flags
);
925 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
929 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
930 out
<< "while" << ' ' << '(' << *test_
<< ')';
931 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
934 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
935 out
<< "with" << ' ' << '(' << *scope_
<< ')';
936 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
939 void CYWord::Output(CYOutput
&out
) const {
941 if (out
.options_
.verbose_
) {
944 sprintf(number
, "%p", this);
949 void CYWord::PropertyName(CYOutput
&out
) const {
953 const char *CYWord::Word() const {