]>
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" << ' ' << '(';
381 declaration_
->Output(out
, CYNoIn
);
382 out
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
385 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
386 out
<< "for" << ' ' << '(';
387 if (initialiser_
!= NULL
)
388 initialiser_
->ForIn(out
, CYNoIn
);
389 out
<< ' ' << "in" << ' ' << *set_
<< ')';
390 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
393 void CYForInComprehension::Output(CYOutput
&out
) const {
394 out
<< "for" << ' ' << '(';
395 declaration_
->Output(out
, CYNoIn
);
396 out
<< ' ' << "in" << ' ' << *set_
<< ')';
399 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
400 // XXX: one could imagine using + here to save a byte
401 bool protect((flags
& CYNoFunction
) != 0);
406 out
<< ' ' << *name_
;
407 out
<< '(' << parameters_
<< ')' << ' ';
417 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
418 CYFunction::Output(out
, flags
);
421 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
422 CYFunction::Output(out
, flags
);
425 void CYFunctionParameter::Output(CYOutput
&out
) const {
426 initialiser_
->Output(out
, CYNoFlags
);
428 out
<< ',' << ' ' << *next_
;
431 const char *CYIdentifier::Word() const {
432 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
435 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
437 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
442 out
<< "if" << ' ' << '(' << *test_
<< ')';
444 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
446 CYFlags
jacks(CYNoDangle
);
450 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
452 unsigned line(out
.position_
.line
);
453 unsigned indent(out
.indent_
);
454 true_
->Single(out
, jacks
, CYCompactShort
);
456 if (false_
!= NULL
) {
457 if (out
.position_
.line
!= line
&& out
.recent_
== indent
)
463 false_
->Single(out
, right
, CYCompactLong
);
470 void CYIfComprehension::Output(CYOutput
&out
) const {
471 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
474 void CYImport::Output(CYOutput
&out
, CYFlags flags
) const {
478 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
479 object_
->Output(out
, Precedence(), CYLeft(flags
));
480 if (const char *word
= property_
->Word())
483 out
<< "->" << '[' << *property_
<< ']';
486 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
487 const char *name(Operator());
488 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
491 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
492 lhs_
->Output(out
, Precedence(), left
);
493 out
<< ' ' << name
<< ' ';
494 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
495 rhs_
->Output(out
, Precedence() - 1, right
);
500 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
501 out
<< *name_
<< ':';
502 statement_
->Single(out
, CYRight(flags
), CYCompactShort
);
505 void CYParenthetical::Output(CYOutput
&out
, CYFlags flags
) const {
507 expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
);
511 void CYStatement::Output(CYOutput
&out
) const {
515 void CYTemplate::Output(CYOutput
&out
, CYFlags flags
) const {
519 void CYTypeArrayOf::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
520 next_
->Output(out
, Precedence(), identifier
);
526 void CYTypeBlockWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
528 next_
->Output(out
, Precedence(), identifier
);
529 out
<< ')' << '(' << parameters_
<< ')';
532 void CYTypeConstant::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
533 out
<< "const" << ' ';
534 next_
->Output(out
, Precedence(), identifier
);
537 void CYTypeFunctionWith::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
538 next_
->Output(out
, Precedence(), identifier
);
539 out
<< '(' << parameters_
<< ')';
542 void CYTypePointerTo::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
544 next_
->Output(out
, Precedence(), identifier
);
547 void CYTypeVolatile::Output(CYOutput
&out
, CYIdentifier
*identifier
) const {
549 next_
->Output(out
, Precedence(), identifier
);
552 void CYTypeModifier::Output(CYOutput
&out
, int precedence
, CYIdentifier
*identifier
) const {
558 bool protect(precedence
> Precedence());
562 Output(out
, identifier
);
567 void CYTypedIdentifier::Output(CYOutput
&out
) const {
568 specifier_
->Output(out
);
569 modifier_
->Output(out
, 0, identifier_
);
572 void CYEncodedType::Output(CYOutput
&out
, CYFlags flags
) const {
573 out
<< "@encode(" << typed_
<< ")";
576 void CYTypedParameter::Output(CYOutput
&out
) const {
579 out
<< ',' << ' ' << next_
;
582 void CYLambda::Output(CYOutput
&out
, CYFlags flags
) const {
583 // XXX: this is seriously wrong
590 void CYTypeDefinition::Output(CYOutput
&out
, CYFlags flags
) const {
591 out
<< "typedef" << ' ' << *typed_
;
594 void CYLetStatement::Output(CYOutput
&out
, CYFlags flags
) const {
595 out
<< "let" << ' ' << '(' << *declarations_
<< ')';
596 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
599 void CYModule::Output(CYOutput
&out
) const {
608 void New::Output(CYOutput
&out
, CYFlags flags
) const {
610 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
611 constructor_
->Output(out
, Precedence(), jacks
);
612 if (arguments_
!= NULL
)
613 out
<< '(' << *arguments_
<< ')';
618 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
622 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
623 std::ostringstream str
;
624 CYNumerify(str
, Value());
625 std::string
value(str
.str());
626 out
<< value
.c_str();
627 // XXX: this should probably also handle hex conversions and exponents
628 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
632 void CYNumber::PropertyName(CYOutput
&out
) const {
633 Output(out
, CYNoFlags
);
636 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
637 bool protect((flags
& CYNoBrace
) != 0);
649 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
650 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
654 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
655 const char *name(Operator());
659 rhs_
->Output(out
, Precedence(), CYRight(flags
));
662 void CYScript::Output(CYOutput
&out
) const {
666 void CYProperty::Output(CYOutput
&out
) const {
668 name_
->PropertyName(out
);
670 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
672 out
<< ',' << '\n' << *next_
;
677 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
681 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
684 out
<< ' ' << *value_
;
688 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
689 call_
->Output(out
, CYLeft(flags
));
691 proc_
->Output(out
, CYRight(flags
));
694 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
695 out
<< '{' << ' ' << '|' << parameters_
<< '|' << '\n';
702 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
704 CYForEach (next
, this) {
705 bool last(next
->next_
== NULL
);
706 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
709 next
->Output(out
, jacks
);
714 void CYStatement::Single(CYOutput
&out
, CYFlags flags
, CYCompactType request
) const {
716 return out
.Terminate();
718 _assert(next_
== NULL
);
720 CYCompactType
compact(Compact());
722 if (compact
>= request
)
732 if (compact
< request
)
736 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
737 std::ostringstream str
;
738 CYStringify(str
, value_
, size_
);
739 out
<< str
.str().c_str();
742 void CYString::PropertyName(CYOutput
&out
) const {
743 if (const char *word
= Word())
749 static const char *Reserved_
[] = {
750 "false", "null", "true",
752 "break", "case", "catch", "continue", "default",
753 "delete", "do", "else", "finally", "for", "function",
754 "if", "in", "instanceof", "new", "return", "switch",
755 "this", "throw", "try", "typeof", "var", "void",
760 "class", "enum", "export", "extends", "import", "super",
762 "abstract", "boolean", "byte", "char", "double", "final",
763 "float", "goto", "int", "long", "native", "short",
764 "synchronized", "throws", "transient", "volatile",
771 const char *CYString::Word() const {
772 if (size_
== 0 || !WordStartRange_
[value_
[0]])
774 for (size_t i(1); i
!= size_
; ++i
)
775 if (!WordEndRange_
[value_
[i
]])
777 const char *value(Value());
778 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
779 if (strcmp(*reserved
, value
) == 0)
784 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
785 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{' << '\n';
792 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
799 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
802 out
<< ' ' << *value_
;
806 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
813 out
<< catch_
<< finally_
;
818 void CYTypeError::Output(CYOutput
&out
) const {
822 void CYTypeLong::Output(CYOutput
&out
) const {
823 out
<< "long" << specifier_
;
826 void CYTypeShort::Output(CYOutput
&out
) const {
827 out
<< "short" << specifier_
;
830 void CYTypeSigned::Output(CYOutput
&out
) const {
831 out
<< "signed" << specifier_
;
834 void CYTypeUnsigned::Output(CYOutput
&out
) const {
835 out
<< "unsigned" << specifier_
;
838 void CYTypeVariable::Output(CYOutput
&out
) const {
842 void CYTypeVoid::Output(CYOutput
&out
) const {
846 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
848 declarations_
->Output(out
, flags
);
852 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
856 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
857 out
<< "while" << ' ' << '(' << *test_
<< ')';
858 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
861 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
862 out
<< "with" << ' ' << '(' << *scope_
<< ')';
863 code_
->Single(out
, CYRight(flags
), CYCompactShort
);
866 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
868 out
<< "objc_getClass(";
869 out
<< '"' << Word() << '"';
874 void CYWord::Output(CYOutput
&out
) const {
876 if (out
.options_
.verbose_
) {
879 sprintf(number
, "%p", this);
884 void CYWord::PropertyName(CYOutput
&out
) const {
888 const char *CYWord::Word() const {