]>
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 CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
189 expression_
->Output(out
, flags
);
191 expression_
->Output(out
, CYLeft(flags
));
193 next_
->Output(out
, CYRight(flags
));
197 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
198 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
199 out
<< ' ' << '?' << ' ';
201 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
202 out
<< ' ' << ':' << ' ';
203 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
206 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
209 out
<< ' ' << *label_
;
213 void CYClause::Output(CYOutput
&out
) const {
216 out
<< "case" << ' ' << *case_
;
226 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
227 out
<< "debugger" << ';';
230 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
232 Output(out
, CYRight(flags
));
235 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
237 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
238 if (initialiser_
!= NULL
) {
239 out
<< ' ' << '=' << ' ';
240 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
244 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
246 declarations_
->Output(out
, CYRight(flags
));
249 void CYDeclarations::Output(CYOutput
&out
) const {
250 Output(out
, CYNoFlags
);
253 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
254 const CYDeclarations
*declaration(this);
258 CYDeclarations
*next(declaration
->next_
);
260 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
262 declaration
->declaration_
->Output(out
, jacks
);
272 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
273 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
274 if (const char *word
= property_
->Word())
277 out
<< '[' << *property_
<< ']';
280 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
283 unsigned line(out
.position_
.line
);
284 unsigned indent(out
.indent_
);
285 code_
->Single(out
, CYCenter(flags
), CYCompactLong
);
287 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
292 out
<< "while" << ' ' << '(' << *test_
<< ')';
295 void CYElementSpread::Output(CYOutput
&out
) const {
296 out
<< "..." << value_
;
299 void CYElementValue::Output(CYOutput
&out
) const {
301 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
302 if (next_
!= NULL
|| value_
== NULL
) {
304 if (next_
!= NULL
&& !next_
->Elision())
311 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
315 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
316 expression_
->Output(out
, flags
| CYNoBF
);
320 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
321 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
324 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
325 Output(out
, flags
| CYNoRightHand
);
328 void CYExpression::Output(CYOutput
&out
) const {
329 Output(out
, CYNoFlags
);
332 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
333 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
334 out
<< '(' << *this << ')';
339 void CYExternal::Output(CYOutput
&out
, CYFlags flags
) const {
340 out
<< "extern" << abi_
<< typed_
<< ';';
343 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
344 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << '{' << code_
<< '}';
347 void CYFinally::Output(CYOutput
&out
) const {
348 out
<< ' ' << "finally" << ' ';
356 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
357 out
<< "for" << ' ' << '(';
358 if (initialiser_
!= NULL
)
359 initialiser_
->Output(out
, CYNoIn
);
365 if (increment_
!= NULL
)
369 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
372 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
373 out
<< "for" << ' ' << "each" << ' ' << '(';
374 initialiser_
->ForIn(out
, CYNoIn
);
375 out
<< ' ' << "in" << ' ' << *set_
<< ')';
376 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
379 void CYForOfComprehension::Output(CYOutput
&out
) const {
380 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
383 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
384 out
<< "for" << ' ' << '(';
385 if (initialiser_
!= NULL
)
386 initialiser_
->ForIn(out
, CYNoIn
);
387 out
<< ' ' << "in" << ' ' << *set_
<< ')';
388 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
391 void CYForInComprehension::Output(CYOutput
&out
) const {
392 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
395 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
396 // XXX: one could imagine using + here to save a byte
397 bool protect((flags
& CYNoFunction
) != 0);
402 out
<< ' ' << *name_
;
403 out
<< '(' << parameters_
<< ')' << ' ';
413 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
414 CYFunction::Output(out
, flags
);
417 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
418 CYFunction::Output(out
, flags
);
421 void CYFunctionParameter::Output(CYOutput
&out
) const {
422 initialiser_
->Output(out
, CYNoFlags
);
424 out
<< ',' << ' ' << *next_
;
427 const char *CYIdentifier::Word() const {
428 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
431 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
433 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
438 out
<< "if" << ' ' << '(' << *test_
<< ')';
440 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
442 CYFlags
jacks(CYNoDangle
);
446 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
448 unsigned line(out
.position_
.line
);
449 unsigned indent(out
.indent_
);
450 true_
->Single(out
, jacks
, CYCompactShort
);
452 if (false_
!= NULL
) {
453 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
459 false_
->Single(out
, right
, CYCompactLong
);
466 void CYIfComprehension::Output(CYOutput
&out
) const {
467 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
470 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
474 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
475 object_
->Output(out
, Precedence(), CYLeft(flags
));
476 if (const char *word
= property_
->Word())
479 out
<< "->" << '[' << *property_
<< ']';
482 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
483 const char *name(Operator());
484 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
487 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
488 lhs_
->Output(out
, Precedence(), left
);
489 out
<< ' ' << name
<< ' ';
490 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
491 rhs_
->Output(out
, Precedence() - 1, right
);
496 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
497 out
<< *name_
<< ':';
498 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
501 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
503 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
507 void CYStatement::Output(CYOutput
&out
) const {
511 void CYTemplate::Output(CYOutput
&out
, CYFlags flags
) const {
515 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
516 next_
->Output(out
, Precedence(), identifier
);
522 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
524 next_
->Output(out
, Precedence(), identifier
);
525 out
<< ')' << '(' << parameters_
<< ')';
528 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
529 out
<< "const" << ' ';
530 next_
->Output(out
, Precedence(), identifier
);
533 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
534 next_
->Output(out
, Precedence(), identifier
);
535 out
<< '(' << parameters_
<< ')';
538 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
540 next_
->Output(out
, Precedence(), identifier
);
543 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
545 next_
->Output(out
, Precedence(), identifier
);
548 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
554 bool protect(precedence
> Precedence());
558 Output(out
, identifier
);
563 void CYTypedIdentifier::Output(CYOutput
&out
) const {
564 specifier_
->Output(out
);
565 modifier_
->Output(out
, 0, identifier_
);
568 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
569 out
<< "@encode(" << typed_
<< ")";
572 void CYTypedParameter::Output(CYOutput
&out
) const {
575 out
<< ',' << ' ' << next_
;
578 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
579 // XXX: this is seriously wrong
586 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
587 out
<< "typedef" << ' ' << *typed_
;
590 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
591 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
592 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
595 void CYModule::Output(CYOutput
&out
) const {
604 void New::Output(CYOutput
&out
, CYFlags flags
) const {
606 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
607 constructor_
->Output(out
, Precedence(), jacks
);
608 if (arguments_
!= NULL
)
609 out
<< '(' << *arguments_
<< ')';
614 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
618 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
619 std::ostringstream str
;
620 CYNumerify(str
, Value());
621 std::string
value(str
.str());
622 out
<< value
.c_str();
623 // XXX: this should probably also handle hex conversions and exponents
624 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
628 void CYNumber::PropertyName(CYOutput
&out
) const {
629 Output(out
, CYNoFlags
);
632 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
633 bool protect((flags
& CYNoBrace
) != 0);
645 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
646 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
650 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
651 const char *name(Operator());
655 rhs_
->Output(out
, Precedence(), CYRight(flags
));
658 void CYScript::Output(CYOutput
&out
) const {
662 void CYProperty::Output(CYOutput
&out
) const {
664 name_
->PropertyName(out
);
666 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
668 out
<< ',' << '\n' << *next_
;
673 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
677 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
680 out
<< ' ' << *value_
;
684 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
685 call_
->Output(out
, CYLeft(flags
));
687 proc_
->Output(out
, CYRight(flags
));
690 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
691 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
698 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
700 CYForEach (next
, this) {
701 bool last(next
->next_
== NULL
);
702 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
705 next
->Output(out
, jacks
);
710 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
712 return out
.Terminate();
714 _assert(next_
== NULL
);
716 CYCompactType
compact(Compact());
718 if (compact
>= request
)
728 if (compact
< request
)
732 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
733 std::ostringstream str
;
734 CYStringify(str
, value_
, size_
);
735 out
<< str
.str().c_str();
738 void CYString::PropertyName(CYOutput
&out
) const {
739 if (const char *word
= Word())
745 static const char *Reserved_
[] = {
746 "false", "null", "true",
748 "break", "case", "catch", "continue", "default",
749 "delete", "do", "else", "finally", "for", "function",
750 "if", "in", "instanceof", "new", "return", "switch",
751 "this", "throw", "try", "typeof", "var", "void",
756 "class", "enum", "export", "extends", "import", "super",
758 "abstract", "boolean", "byte", "char", "double", "final",
759 "float", "goto", "int", "long", "native", "short",
760 "synchronized", "throws", "transient", "volatile",
767 const char *CYString::Word() const {
768 if (size_
== 0 || !WordStartRange_
[value_
[0]])
770 for (size_t i(1); i
!= size_
; ++i
)
771 if (!WordEndRange_
[value_
[i
]])
773 const char *value(Value());
774 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
775 if (strcmp(*reserved
, value
) == 0)
780 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
781 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
788 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
795 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
798 out
<< ' ' << *value_
;
802 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
809 out
<< catch_
<< finally_
;
814 void CYTypeError::Output(CYOutput
&out
) const {
818 void CYTypeLong::Output(CYOutput
&out
) const {
819 out
<< "long" << specifier_
;
822 void CYTypeShort::Output(CYOutput
&out
) const {
823 out
<< "short" << specifier_
;
826 void CYTypeSigned::Output(CYOutput
&out
) const {
827 out
<< "signed" << specifier_
;
830 void CYTypeUnsigned::Output(CYOutput
&out
) const {
831 out
<< "unsigned" << specifier_
;
834 void CYTypeVariable::Output(CYOutput
&out
) const {
838 void CYTypeVoid::Output(CYOutput
&out
) const {
842 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
844 declarations_
->Output(out
, flags
);
848 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
852 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
853 out
<< "while" << ' ' << '(' << *test_
<< ')';
854 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
857 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
858 out
<< "with" << ' ' << '(' << *scope_
<< ')';
859 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
862 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
864 out
<< "objc_getClass(";
865 out
<< '"' << Word() << '"';
870 void CYWord::Output(CYOutput
&out
) const {
872 if (out
.options_
.verbose_
) {
875 sprintf(number
, "%p", this);
880 void CYWord::PropertyName(CYOutput
&out
) const {
884 const char *CYWord::Word() const {