]>
git.saurik.com Git - cycript.git/blob - Output.cpp
cdfe1bd1e4a3c5c8a49c8f3deeb47678dd2549c2
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"
27 void CYOutput::Terminate() {
32 CYOutput
&CYOutput::operator <<(char rhs
) {
33 if (rhs
== ' ' || rhs
== '\n')
39 for (unsigned i(0); i
!= indent_
; ++i
)
42 else if (rhs
== '\r') {
54 if (mode_
== Terminated
&& rhs
!= '}') {
66 } else if (rhs
== '+') {
70 } else if (rhs
== '-') {
71 if (mode_
== NoHyphen
)
74 } else if (WordEndRange_
[rhs
]) {
75 if (mode_
== NoLetter
)
87 CYOutput
&CYOutput::operator <<(const char *rhs
) {
88 size_t size(strlen(rhs
));
93 if (mode_
== Terminated
)
96 mode_
== NoPlus
&& *rhs
== '+' ||
97 mode_
== NoHyphen
&& *rhs
== '-' ||
98 mode_
== NoLetter
&& WordEndRange_
[*rhs
]
102 char last(rhs
[size
- 1]);
103 if (WordEndRange_
[last
] || last
== '/')
113 void CYArgument::Output(CYOutput
&out
) const {
120 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
123 out
<< ' ' << *next_
;
127 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
128 out
<< '[' << elements_
<< ']';
131 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
132 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
135 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
136 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
137 out
<< ' ' << Operator() << ' ';
138 rhs_
->Output(out
, Precedence(), CYRight(flags
));
141 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
149 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
150 out
<< (Value() ? "true" : "false");
153 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
156 out
<< ' ' << *label_
;
160 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
161 bool protect((flags
& CYNoCall
) != 0);
164 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
165 out
<< '(' << arguments_
<< ')';
173 void Catch::Output(CYOutput
&out
) const {
174 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ';
184 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
191 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
193 expression_
->Output(out
, flags
);
195 expression_
->Output(out
, CYLeft(flags
));
197 next_
->Output(out
, CYRight(flags
));
201 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
202 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
203 out
<< ' ' << '?' << ' ';
205 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
206 out
<< ' ' << ':' << ' ';
207 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
210 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
213 out
<< ' ' << *label_
;
217 void CYClause::Output(CYOutput
&out
) const {
219 out
<< "case" << ' ' << *case_
;
227 void CYDebugger::Output(CYOutput
&out
, CYFlags flags
) const {
228 out
<< "debugger" << ';';
231 void CYDeclaration::ForIn(CYOutput
&out
, CYFlags flags
) const {
233 Output(out
, CYRight(flags
));
236 void CYDeclaration::Output(CYOutput
&out
, CYFlags flags
) const {
238 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
239 if (initialiser_
!= NULL
) {
240 out
<< ' ' << '=' << ' ';
241 initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
245 void CYForDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
247 declarations_
->Output(out
, CYRight(flags
));
250 void CYDeclarations::Output(CYOutput
&out
) const {
251 Output(out
, CYNoFlags
);
254 void CYDeclarations::Output(CYOutput
&out
, CYFlags flags
) const {
255 const CYDeclarations
*declaration(this);
259 CYDeclarations
*next(declaration
->next_
);
261 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
263 declaration
->declaration_
->Output(out
, jacks
);
273 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
274 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
275 if (const char *word
= property_
->Word())
278 out
<< '[' << *property_
<< ']';
281 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
283 code_
->Single(out
, CYCenter(flags
));
284 out
<< "while" << ' ' << '(' << *test_
<< ')';
287 void CYElement::Output(CYOutput
&out
) const {
289 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
290 if (next_
!= NULL
|| value_
== NULL
) {
292 if (next_
!= NULL
&& next_
->value_
!= NULL
)
299 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
303 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
304 expression_
->Output(out
, flags
| CYNoBF
);
308 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
309 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
312 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
313 Output(out
, flags
| CYNoRightHand
);
316 void CYExpression::Output(CYOutput
&out
) const {
317 Output(out
, CYNoFlags
);
320 void CYExpression::Output(CYOutput
&out
, int precedence
, CYFlags flags
) const {
321 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
322 out
<< '(' << *this << ')';
327 void CYExternal::Output(CYOutput
&out
, CYFlags flags
) const {
328 out
<< "extern" << abi_
<< typed_
<< ';';
331 void CYFatArrow::Output(CYOutput
&out
, CYFlags flags
) const {
332 out
<< '(' << parameters_
<< ')' << ' ' << "=>" << ' ' << '{' << code_
<< '}';
335 void CYFinally::Output(CYOutput
&out
) const {
336 out
<< ' ' << "finally" << ' ';
344 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
345 out
<< "for" << ' ' << '(';
346 if (initialiser_
!= NULL
)
347 initialiser_
->Output(out
, CYNoIn
);
353 if (increment_
!= NULL
)
357 code_
->Single(out
, CYRight(flags
));
360 void CYForOf::Output(CYOutput
&out
, CYFlags flags
) const {
361 out
<< "for" << ' ' << "each" << ' ' << '(';
362 initialiser_
->ForIn(out
, CYNoIn
);
363 out
<< "in" << *set_
<< ')';
364 code_
->Single(out
, CYRight(flags
));
367 void CYForOfComprehension::Output(CYOutput
&out
) const {
368 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
371 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
372 out
<< "for" << ' ' << '(';
373 if (initialiser_
!= NULL
)
374 initialiser_
->ForIn(out
, CYNoIn
);
375 out
<< "in" << *set_
<< ')';
376 code_
->Single(out
, CYRight(flags
));
379 void CYForInComprehension::Output(CYOutput
&out
) const {
380 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
383 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
384 // XXX: one could imagine using + here to save a byte
385 bool protect((flags
& CYNoFunction
) != 0);
390 out
<< ' ' << *name_
;
391 out
<< '(' << parameters_
<< ')' << ' ';
401 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
402 CYFunction::Output(out
, flags
);
405 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
406 CYFunction::Output(out
, flags
);
409 void CYFunctionParameter::Output(CYOutput
&out
) const {
410 initialiser_
->Output(out
, CYNoFlags
);
412 out
<< ',' << ' ' << *next_
;
415 const char *CYIdentifier::Word() const {
416 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
419 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
421 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
426 out
<< "if" << ' ' << '(' << *test_
<< ')';
428 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
430 CYFlags
jacks(CYNoDangle
);
434 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
436 true_
->Single(out
, jacks
);
438 if (false_
!= NULL
) {
439 out
<< '\t' << "else";
440 false_
->Single(out
, right
);
447 void CYIfComprehension::Output(CYOutput
&out
) const {
448 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
451 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
455 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
456 object_
->Output(out
, Precedence(), CYLeft(flags
));
457 if (const char *word
= property_
->Word())
460 out
<< "->" << '[' << *property_
<< ']';
463 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
464 const char *name(Operator());
465 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
468 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
469 lhs_
->Output(out
, Precedence(), left
);
470 out
<< ' ' << name
<< ' ';
471 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
472 rhs_
->Output(out
, Precedence() - 1, right
);
477 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
478 out
<< *name_
<< ':' << ' ';
479 statement_
->Single(out
, CYRight(flags
));
482 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
484 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
488 void CYStatement::Output(CYOutput
&out
) const {
492 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
493 next_
->Output(out
, Precedence(), identifier
);
499 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
501 next_
->Output(out
, Precedence(), identifier
);
502 out
<< ')' << '(' << parameters_
<< ')';
505 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
507 next_
->Output(out
, Precedence(), identifier
);
510 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
511 next_
->Output(out
, Precedence(), identifier
);
512 out
<< '(' << parameters_
<< ')';
515 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
517 next_
->Output(out
, Precedence(), identifier
);
520 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
522 next_
->Output(out
, Precedence(), identifier
);
525 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
531 bool protect(precedence
> Precedence());
535 Output(out
, identifier
);
540 void CYTypedIdentifier::Output(CYOutput
&out
) const {
541 specifier_
->Output(out
);
542 modifier_
->Output(out
, 0, identifier_
);
545 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
546 out
<< "@encode(" << typed_
<< ")";
549 void CYTypedParameter::Output(CYOutput
&out
) const {
552 out
<< ',' << ' ' << next_
;
555 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
556 // XXX: this is seriously wrong
563 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
564 out
<< "typedef" << *typed_
;
567 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
568 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
569 code_
->Single(out
, CYRight(flags
));
572 void CYModule::Output(CYOutput
&out
) const {
581 void New::Output(CYOutput
&out
, CYFlags flags
) const {
583 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
584 constructor_
->Output(out
, Precedence(), jacks
);
585 if (arguments_
!= NULL
)
586 out
<< '(' << *arguments_
<< ')';
591 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
595 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
596 std::ostringstream str
;
597 CYNumerify(str
, Value());
598 std::string
value(str
.str());
599 out
<< value
.c_str();
600 // XXX: this should probably also handle hex conversions and exponents
601 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
605 void CYNumber::PropertyName(CYOutput
&out
) const {
606 Output(out
, CYNoFlags
);
609 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
610 bool protect((flags
& CYNoBrace
) != 0);
622 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
623 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
627 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
628 const char *name(Operator());
632 rhs_
->Output(out
, Precedence(), CYRight(flags
));
635 void CYProgram::Output(CYOutput
&out
) const {
639 void CYProperty::Output(CYOutput
&out
) const {
641 name_
->PropertyName(out
);
643 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
645 out
<< ',' << '\n' << *next_
;
650 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
654 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
657 out
<< ' ' << *value_
;
661 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
662 call_
->Output(out
, CYLeft(flags
));
664 proc_
->Output(out
, CYRight(flags
));
667 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
668 // XXX: this is not outputting the parameters
676 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
678 CYForEach (next
, this) {
679 bool last(next
->next_
== NULL
);
680 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
683 next
->Output(out
, jacks
);
688 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
690 return out
.Terminate();
692 _assert(next_
== NULL
);
701 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
702 std::ostringstream str
;
703 CYStringify(str
, value_
, size_
);
704 out
<< str
.str().c_str();
707 void CYString::PropertyName(CYOutput
&out
) const {
708 if (const char *word
= Word())
714 static const char *Reserved_
[] = {
715 "false", "null", "true",
717 "break", "case", "catch", "continue", "default",
718 "delete", "do", "else", "finally", "for", "function",
719 "if", "in", "instanceof", "new", "return", "switch",
720 "this", "throw", "try", "typeof", "var", "void",
725 "class", "enum", "export", "extends", "import", "super",
727 "abstract", "boolean", "byte", "char", "double", "final",
728 "float", "goto", "int", "long", "native", "short",
729 "synchronized", "throws", "transient", "volatile",
736 const char *CYString::Word() const {
737 if (size_
== 0 || !WordStartRange_
[value_
[0]])
739 for (size_t i(1); i
!= size_
; ++i
)
740 if (!WordEndRange_
[value_
[i
]])
742 const char *value(Value());
743 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
744 if (strcmp(*reserved
, value
) == 0)
749 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
750 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
755 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
762 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
765 out
<< ' ' << *value_
;
769 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
776 out
<< catch_
<< finally_
;
781 void CYTypeError::Output(CYOutput
&out
) const {
785 void CYTypeLong::Output(CYOutput
&out
) const {
786 out
<< "long" << specifier_
;
789 void CYTypeShort::Output(CYOutput
&out
) const {
790 out
<< "short" << specifier_
;
793 void CYTypeSigned::Output(CYOutput
&out
) const {
794 out
<< "signed" << specifier_
;
797 void CYTypeUnsigned::Output(CYOutput
&out
) const {
798 out
<< "unsigned" << specifier_
;
801 void CYTypeVariable::Output(CYOutput
&out
) const {
805 void CYTypeVoid::Output(CYOutput
&out
) const {
809 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
811 declarations_
->Output(out
, flags
);
815 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
819 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
820 out
<< "while" << '(' << *test_
<< ')';
821 code_
->Single(out
, CYRight(flags
));
824 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
825 out
<< "with" << '(' << *scope_
<< ')';
826 code_
->Single(out
, CYRight(flags
));
829 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
831 out
<< "objc_getClass(";
832 out
<< '"' << Word() << '"';
837 void CYWord::Output(CYOutput
&out
) const {
839 if (out
.options_
.verbose_
)
840 out
.out_
<< '@' << this;
843 void CYWord::PropertyName(CYOutput
&out
) const {
847 const char *CYWord::Word() const {