]>
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_
;
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 CYImportDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
527 void CYIndirect::Output(CYOutput
&out
, CYFlags flags
) const {
529 rhs_
->Output(out
, Precedence(), CYRight(flags
));
532 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
533 object_
->Output(out
, Precedence(), CYLeft(flags
));
534 if (const char *word
= property_
->Word())
537 out
<< "->" << '[' << *property_
<< ']';
540 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
541 const char *name(Operator());
542 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
545 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
546 lhs_
->Output(out
, Precedence(), left
);
547 out
<< ' ' << name
<< ' ';
548 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
549 rhs_
->Output(out
, Precedence() - 1, right
);
554 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
555 out
<< *name_
<< ':';
556 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
559 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
561 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
565 void CYStatement::Output(CYOutput
&out
) const {
569 void CYTemplate::Output(CYOutput
&out
, CYFlags flags
) const {
573 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
574 next_
->Output(out
, Precedence(), identifier
);
580 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
582 next_
->Output(out
, Precedence(), identifier
);
583 out
<< ')' << '(' << parameters_
<< ')';
586 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
587 out
<< "const" << ' ';
588 next_
->Output(out
, Precedence(), identifier
);
591 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
592 next_
->Output(out
, Precedence(), identifier
);
593 out
<< '(' << parameters_
<< ')';
596 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
598 next_
->Output(out
, Precedence(), identifier
);
601 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
603 next_
->Output(out
, Precedence(), identifier
);
606 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
612 bool protect(precedence
> Precedence());
616 Output(out
, identifier
);
621 void CYTypedIdentifier::Output(CYOutput
&out
) const {
622 specifier_
->Output(out
);
623 modifier_
->Output(out
, 0, identifier_
);
626 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
627 out
<< "@encode(" << typed_
<< ")";
630 void CYTypedParameter::Output(CYOutput
&out
) const {
633 out
<< ',' << ' ' << next_
;
636 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
637 // XXX: this is seriously wrong
644 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
645 out
<< "typedef" << ' ' << *typed_
;
649 void CYTypeExpression::Output(CYOutput
&out
, CYFlags flags
) const {
650 out
<< '(' << "typedef" << ' ' << *typed_
<< ')';
653 void CYLexical::Output(CYOutput
&out
, CYFlags flags
) const {
655 bindings_
->Output(out
, flags
); // XXX: flags
659 void CYModule::Output(CYOutput
&out
) const {
668 void New::Output(CYOutput
&out
, CYFlags flags
) const {
670 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
671 constructor_
->Output(out
, Precedence(), jacks
);
672 if (arguments_
!= NULL
)
673 out
<< '(' << *arguments_
<< ')';
678 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
682 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
683 std::ostringstream str
;
684 CYNumerify(str
, Value());
685 std::string
value(str
.str());
686 out
<< value
.c_str();
687 // XXX: this should probably also handle hex conversions and exponents
688 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
692 void CYNumber::PropertyName(CYOutput
&out
) const {
693 Output(out
, CYNoFlags
);
696 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
697 bool protect((flags
& CYNoBrace
) != 0);
709 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
710 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
714 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
715 const char *name(Operator());
719 rhs_
->Output(out
, Precedence(), CYRight(flags
));
722 void CYScript::Output(CYOutput
&out
) const {
726 void CYProperty::Output(CYOutput
&out
) const {
727 if (next_
!= NULL
|| out
.pretty_
)
729 out
<< '\n' << next_
;
732 void CYPropertyGetter::Output(CYOutput
&out
) const {
734 name_
->PropertyName(out
);
735 CYFunction::Output(out
);
736 CYProperty::Output(out
);
739 void CYPropertyMethod::Output(CYOutput
&out
) const {
740 name_
->PropertyName(out
);
741 CYFunction::Output(out
);
742 CYProperty::Output(out
);
745 void CYPropertySetter::Output(CYOutput
&out
) const {
747 name_
->PropertyName(out
);
748 CYFunction::Output(out
);
749 CYProperty::Output(out
);
752 void CYPropertyValue::Output(CYOutput
&out
) const {
754 name_
->PropertyName(out
);
756 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
757 CYProperty::Output(out
);
760 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
764 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
767 out
<< ' ' << *value_
;
771 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
772 call_
->Output(out
, CYLeft(flags
));
774 proc_
->Output(out
, CYRight(flags
));
777 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
778 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
785 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
787 CYForEach (next
, this) {
788 bool last(next
->next_
== NULL
);
789 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
792 next
->Output(out
, jacks
);
797 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
799 return out
.Terminate();
801 _assert(next_
== NULL
);
803 CYCompactType
compact(Compact());
805 if (compact
>= request
)
815 if (compact
< request
)
819 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
820 std::ostringstream str
;
821 CYStringify(str
, value_
, size_
);
822 out
<< str
.str().c_str();
825 void CYString::PropertyName(CYOutput
&out
) const {
826 if (const char *word
= Word())
832 static const char *Reserved_
[] = {
833 "false", "null", "true",
835 "break", "case", "catch", "continue", "default",
836 "delete", "do", "else", "finally", "for", "function",
837 "if", "in", "instanceof", "new", "return", "switch",
838 "this", "throw", "try", "typeof", "var", "void",
843 "class", "enum", "export", "extends", "import", "super",
845 "abstract", "boolean", "byte", "char", "double", "final",
846 "float", "goto", "int", "long", "native", "short",
847 "synchronized", "throws", "transient", "volatile",
854 const char *CYString::Word() const {
855 if (size_
== 0 || !WordStartRange_
[value_
[0]])
857 for (size_t i(1); i
!= size_
; ++i
)
858 if (!WordEndRange_
[value_
[i
]])
860 const char *value(Value());
861 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
862 if (strcmp(*reserved
, value
) == 0)
867 void CYSuperAccess::Output(CYOutput
&out
, CYFlags flags
) const {
869 if (const char *word
= property_
->Word())
872 out
<< '[' << *property_
<< ']';
875 void CYSuperCall::Output(CYOutput
&out
, CYFlags flags
) const {
876 out
<< "super" << '(' << arguments_
<< ')';
879 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
880 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
887 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
894 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
897 out
<< ' ' << *value_
;
901 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
908 out
<< catch_
<< finally_
;
913 void CYTypeError::Output(CYOutput
&out
) const {
917 void CYTypeLong::Output(CYOutput
&out
) const {
918 out
<< "long" << specifier_
;
921 void CYTypeShort::Output(CYOutput
&out
) const {
922 out
<< "short" << specifier_
;
925 void CYTypeSigned::Output(CYOutput
&out
) const {
926 out
<< "signed" << specifier_
;
929 void CYTypeStruct::Output(CYOutput
&out
) const {
930 out
<< "struct" << ' ';
932 out
<< *name_
<< ' ';
935 CYForEach (field
, fields_
) {
936 out
<< '\t' << *field
->typed_
;
944 void CYTypeUnsigned::Output(CYOutput
&out
) const {
945 out
<< "unsigned" << specifier_
;
948 void CYTypeVariable::Output(CYOutput
&out
) const {
952 void CYTypeVoid::Output(CYOutput
&out
) const {
956 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
958 bindings_
->Output(out
, flags
); // XXX: flags
962 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
966 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
967 out
<< "while" << ' ' << '(' << *test_
<< ')';
968 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
971 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
972 out
<< "with" << ' ' << '(' << *scope_
<< ')';
973 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
976 void CYWord::Output(CYOutput
&out
) const {
978 if (out
.options_
.verbose_
) {
981 sprintf(number
, "%p", this);
986 void CYWord::PropertyName(CYOutput
&out
) const {
990 const char *CYWord::Word() const {