]>
git.saurik.com Git - cycript.git/blob - Output.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2010 Jay Freeman (saurik)
5 /* GNU Lesser General Public License, Version 3 {{{ */
7 * Cycript is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
12 * Cycript is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
22 #include "cycript.hpp"
27 _finline CYFlags
operator ~(CYFlags rhs
) {
28 return static_cast<CYFlags
>(~static_cast<unsigned>(rhs
));
31 _finline CYFlags
operator &(CYFlags lhs
, CYFlags rhs
) {
32 return static_cast<CYFlags
>(static_cast<unsigned>(lhs
) & static_cast<unsigned>(rhs
));
35 _finline CYFlags
operator |(CYFlags lhs
, CYFlags rhs
) {
36 return static_cast<CYFlags
>(static_cast<unsigned>(lhs
) | static_cast<unsigned>(rhs
));
39 _finline CYFlags
&operator |=(CYFlags
&lhs
, CYFlags rhs
) {
40 return lhs
= lhs
| rhs
;
43 _finline CYFlags
CYLeft(CYFlags flags
) {
44 return flags
& ~(CYNoDangle
| CYNoInteger
);
47 _finline CYFlags
CYRight(CYFlags flags
) {
48 return flags
& ~CYNoBF
;
51 _finline CYFlags
CYCenter(CYFlags flags
) {
52 return CYLeft(CYRight(flags
));
55 void CYOutput::Terminate() {
60 CYOutput
&CYOutput::operator <<(char rhs
) {
61 if (rhs
== ' ' || rhs
== '\n')
67 for (unsigned i(0); i
!= indent_
; ++i
)
70 else if (rhs
== '\r') {
82 if (mode_
== Terminated
&& rhs
!= '}') {
94 } else if (rhs
== '+') {
98 } else if (rhs
== '-') {
99 if (mode_
== NoHyphen
)
102 } else if (WordEndRange_
[rhs
]) {
103 if (mode_
== NoLetter
)
115 CYOutput
&CYOutput::operator <<(const char *rhs
) {
116 size_t size(strlen(rhs
));
119 return *this << *rhs
;
121 if (mode_
== Terminated
)
124 mode_
== NoPlus
&& *rhs
== '+' ||
125 mode_
== NoHyphen
&& *rhs
== '-' ||
126 mode_
== NoLetter
&& WordEndRange_
[*rhs
]
130 if (WordEndRange_
[rhs
[size
- 1]])
140 void CYArgument::Output(CYOutput
&out
) const {
147 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
149 if (next_
->name_
== NULL
)
151 out
<< ' ' << *next_
;
155 void CYArray::Output(CYOutput
&out
, CYFlags flags
) const {
156 out
<< '[' << elements_
<< ']';
159 void CYArrayComprehension::Output(CYOutput
&out
, CYFlags flags
) const {
160 out
<< '[' << *expression_
<< ' ' << *comprehensions_
<< ']';
163 void CYAssignment::Output(CYOutput
&out
, CYFlags flags
) const {
164 lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
);
165 out
<< ' ' << Operator() << ' ';
166 rhs_
->Output(out
, Precedence(), CYRight(flags
));
169 void CYBlock::Output(CYOutput
&out
) const {
172 if (statements_
!= NULL
)
173 statements_
->Multiple(out
);
178 void CYBlock::Output(CYOutput
&out
, CYFlags flags
) const {
179 if (statements_
== NULL
)
181 else if (statements_
->next_
== NULL
)
182 statements_
->Single(out
, flags
);
187 void CYBoolean::Output(CYOutput
&out
, CYFlags flags
) const {
188 out
<< (Value() ? "true" : "false");
191 void CYBreak::Output(CYOutput
&out
, CYFlags flags
) const {
194 out
<< ' ' << *label_
;
198 void CYCall::Output(CYOutput
&out
, CYFlags flags
) const {
199 bool protect((flags
& CYNoCall
) != 0);
202 function_
->Output(out
, Precedence(), protect
? CYNoFlags
: flags
);
203 out
<< '(' << arguments_
<< ')';
211 void Catch::Output(CYOutput
&out
) const {
212 out
<< ' ' << "catch" << ' ' << '(' << *name_
<< ')' << ' ' << code_
;
217 void CYComment::Output(CYOutput
&out
, CYFlags flags
) const {
224 void CYCompound::Output(CYOutput
&out
, CYFlags flags
) const {
225 if (CYExpression
*expression
= expressions_
)
226 if (CYExpression
*next
= expression
->next_
) {
227 expression
->Output(out
, CYLeft(flags
));
228 CYFlags
center(CYCenter(flags
));
229 while (next
!= NULL
) {
232 next
= expression
->next_
;
233 CYFlags
right(next
!= NULL
? center
: CYRight(flags
));
234 expression
->Output(out
, right
);
237 expression
->Output(out
, flags
);
240 void CYCondition::Output(CYOutput
&out
, CYFlags flags
) const {
241 test_
->Output(out
, Precedence() - 1, CYLeft(flags
));
242 out
<< ' ' << '?' << ' ';
244 true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
245 out
<< ' ' << ':' << ' ';
246 false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
));
249 void CYContinue::Output(CYOutput
&out
, CYFlags flags
) const {
252 out
<< ' ' << *label_
;
256 void CYClause::Output(CYOutput
&out
) const {
258 out
<< "case" << ' ' << *case_
;
262 if (statements_
!= NULL
)
263 statements_
->Multiple(out
);
267 const char *CYDeclaration::ForEachIn() const {
268 return identifier_
->Word();
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 CYDeclarations::For(CYOutput
&out
) const {
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);
298 CYDeclarations
*next(declaration
->next_
);
299 CYFlags
jacks(first
? CYLeft(flags
) : next
== NULL
? CYRight(flags
) : CYCenter(flags
));
301 declaration
->declaration_
->Output(out
, jacks
);
310 void CYDirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
311 object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
);
312 if (const char *word
= property_
->Word())
315 out
<< '[' << *property_
<< ']';
318 void CYDoWhile::Output(CYOutput
&out
, CYFlags flags
) const {
320 code_
->Single(out
, CYCenter(flags
));
321 out
<< "while" << ' ' << '(' << *test_
<< ')';
324 void CYElement::Output(CYOutput
&out
) const {
326 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
327 if (next_
!= NULL
|| value_
== NULL
) {
329 if (next_
!= NULL
&& next_
->value_
!= NULL
)
336 void CYEmpty::Output(CYOutput
&out
, CYFlags flags
) const {
340 void CYExpress::Output(CYOutput
&out
, CYFlags flags
) const {
341 expression_
->Output(out
, flags
| CYNoBF
);
345 void CYExpression::ClassName(CYOutput
&out
, bool object
) const {
346 Output(out
, CYAssign::Precedence_
, CYNoFlags
);
349 const char *CYExpression::ForEachIn() const {
353 void CYExpression::For(CYOutput
&out
) const {
357 void CYExpression::ForIn(CYOutput
&out
, CYFlags flags
) const {
358 Output(out
, flags
| CYNoRightHand
);
361 void CYExpression::Output(CYOutput
&out
) const {
362 Output(out
, CYNoFlags
);
365 void CYExpression::Output(CYOutput
&out
, unsigned precedence
, CYFlags flags
) const {
366 if (precedence
< Precedence() || (flags
& CYNoRightHand
) != 0 && RightHand())
367 out
<< '(' << *this << ')';
372 void CYFinally::Output(CYOutput
&out
) const {
373 out
<< ' ' << "finally" << ' ' << code_
;
376 void CYFor::Output(CYOutput
&out
, CYFlags flags
) const {
377 out
<< "for" << ' ' << '(';
378 if (initialiser_
!= NULL
)
379 initialiser_
->For(out
);
385 if (increment_
!= NULL
)
389 code_
->Single(out
, CYRight(flags
));
392 void CYForEachIn::Output(CYOutput
&out
, CYFlags flags
) const {
393 out
<< "for" << ' ' << "each" << ' ' << '(';
394 initialiser_
->ForIn(out
, CYNoIn
);
395 out
<< "in" << *set_
<< ')';
396 code_
->Single(out
, CYRight(flags
));
399 void CYForEachInComprehension::Output(CYOutput
&out
) const {
400 out
<< "for" << ' ' << "each" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')' << next_
;
403 void CYForIn::Output(CYOutput
&out
, CYFlags flags
) const {
404 out
<< "for" << ' ' << '(';
405 if (initialiser_
!= NULL
)
406 initialiser_
->ForIn(out
, CYNoIn
);
407 out
<< "in" << *set_
<< ')';
408 code_
->Single(out
, CYRight(flags
));
411 void CYForInComprehension::Output(CYOutput
&out
) const {
412 out
<< "for" << ' ' << '(' << *name_
<< ' ' << "in" << ' ' << *set_
<< ')';
415 void CYFunction::Output(CYOutput
&out
, CYFlags flags
) const {
416 // XXX: one could imagine using + here to save a byte
417 bool protect((flags
& CYNoFunction
) != 0);
422 out
<< ' ' << *name_
;
423 out
<< '(' << parameters_
<< ')';
429 void CYFunctionExpression::Output(CYOutput
&out
, CYFlags flags
) const {
430 CYFunction::Output(out
, flags
);
433 void CYFunctionStatement::Output(CYOutput
&out
, CYFlags flags
) const {
434 CYFunction::Output(out
, flags
);
437 void CYFunctionParameter::Output(CYOutput
&out
) const {
440 out
<< ',' << ' ' << *next_
;
443 const char *CYIdentifier::Word() const {
444 return replace_
== NULL
|| replace_
== this ? CYWord::Word() : replace_
->Word();
447 void CYIf::Output(CYOutput
&out
, CYFlags flags
) const {
449 if (false_
== NULL
&& (flags
& CYNoDangle
) != 0) {
454 out
<< "if" << ' ' << '(' << *test_
<< ')';
456 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
458 CYFlags
jacks(CYNoDangle
);
462 jacks
|= protect
? CYNoFlags
: CYCenter(flags
);
464 true_
->Single(out
, jacks
);
466 if (false_
!= NULL
) {
467 out
<< '\t' << "else";
468 false_
->Single(out
, right
);
475 void CYIfComprehension::Output(CYOutput
&out
) const {
476 out
<< "if" << ' ' << '(' << *test_
<< ')' << next_
;
479 void CYIndirectMember::Output(CYOutput
&out
, CYFlags flags
) const {
480 object_
->Output(out
, Precedence(), CYLeft(flags
));
481 if (const char *word
= property_
->Word())
484 out
<< "->" << '[' << *property_
<< ']';
487 void CYInfix::Output(CYOutput
&out
, CYFlags flags
) const {
488 const char *name(Operator());
489 bool protect((flags
& CYNoIn
) != 0 && strcmp(name
, "in") == 0);
492 CYFlags
left(protect
? CYNoFlags
: CYLeft(flags
));
493 lhs_
->Output(out
, Precedence(), left
);
494 out
<< ' ' << name
<< ' ';
495 CYFlags
right(protect
? CYNoFlags
: CYRight(flags
));
496 rhs_
->Output(out
, Precedence() - 1, right
);
501 void CYLabel::Output(CYOutput
&out
, CYFlags flags
) const {
502 out
<< *name_
<< ':' << ' ';
503 statement_
->Single(out
, CYRight(flags
));
506 void CYLet::Output(CYOutput
&out
, CYFlags flags
) const {
507 out
<< "let" << ' ' << '(' << *declarations_
<< ')' << ' ' << code_
;
513 void New::Output(CYOutput
&out
, CYFlags flags
) const {
515 CYFlags
jacks(CYNoCall
| CYCenter(flags
));
516 constructor_
->Output(out
, Precedence(), jacks
);
517 if (arguments_
!= NULL
)
518 out
<< '(' << *arguments_
<< ')';
523 void CYNull::Output(CYOutput
&out
, CYFlags flags
) const {
527 void CYNumber::Output(CYOutput
&out
, CYFlags flags
) const {
528 std::ostringstream str
;
529 CYNumerify(str
, Value());
530 std::string
value(str
.str());
531 out
<< value
.c_str();
532 // XXX: this should probably also handle hex conversions and exponents
533 if ((flags
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
)
537 void CYNumber::PropertyName(CYOutput
&out
) const {
538 Output(out
, CYNoFlags
);
541 void CYObject::Output(CYOutput
&out
, CYFlags flags
) const {
542 bool protect((flags
& CYNoBrace
) != 0);
554 void CYOptionalFunctionParameter::Output(CYOutput
&out
) const {
555 out
<< *name_
<< '=';
556 initializer_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
558 out
<< ',' << ' ' << *next_
;
561 void CYPostfix::Output(CYOutput
&out
, CYFlags flags
) const {
562 lhs_
->Output(out
, Precedence(), CYLeft(flags
));
566 void CYPrefix::Output(CYOutput
&out
, CYFlags flags
) const {
567 const char *name(Operator());
571 rhs_
->Output(out
, Precedence(), CYRight(flags
));
574 void CYProgram::Output(CYOutput
&out
) const {
575 if (statements_
!= NULL
)
576 statements_
->Multiple(out
);
579 void CYProperty::Output(CYOutput
&out
) const {
581 name_
->PropertyName(out
);
583 value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
);
585 out
<< ',' << '\n' << *next_
;
590 void CYRegEx::Output(CYOutput
&out
, CYFlags flags
) const {
594 void CYReturn::Output(CYOutput
&out
, CYFlags flags
) const {
597 out
<< ' ' << *value_
;
601 void CYRubyBlock::Output(CYOutput
&out
, CYFlags flags
) const {
602 call_
->Output(out
, CYLeft(flags
));
604 proc_
->Output(out
, CYRight(flags
));
607 void CYRubyProc::Output(CYOutput
&out
, CYFlags flags
) const {
608 // XXX: this is not outputting the parameters
612 void CYStatement::Multiple(CYOutput
&out
, CYFlags flags
) const {
614 CYForEach (next
, this) {
615 bool last(next
->next_
== NULL
);
616 CYFlags
jacks(first
? last
? flags
: CYLeft(flags
) : last
? CYRight(flags
) : CYCenter(flags
));
619 next
->Output(out
, jacks
);
624 void CYStatement::Single(CYOutput
&out
, CYFlags flags
) const {
625 _assert(next_
== NULL
);
634 void CYString::Output(CYOutput
&out
, CYFlags flags
) const {
635 std::ostringstream str
;
636 CYStringify(str
, value_
, size_
);
637 out
<< str
.str().c_str();
640 void CYString::PropertyName(CYOutput
&out
) const {
641 if (const char *word
= Word())
647 static const char *Reserved_
[] = {
648 "false", "null", "true",
650 "break", "case", "catch", "continue", "default",
651 "delete", "do", "else", "finally", "for", "function",
652 "if", "in", "instanceof", "new", "return", "switch",
653 "this", "throw", "try", "typeof", "var", "void",
658 "class", "enum", "export", "extends", "import", "super",
660 "abstract", "boolean", "byte", "char", "double", "final",
661 "float", "goto", "int", "long", "native", "short",
662 "synchronized", "throws", "transient", "volatile",
669 const char *CYString::Word() const {
670 if (size_
== 0 || !WordStartRange_
[value_
[0]])
672 for (size_t i(1); i
!= size_
; ++i
)
673 if (!WordEndRange_
[value_
[i
]])
675 const char *value(Value());
676 for (const char **reserved(Reserved_
); *reserved
!= NULL
; ++reserved
)
677 if (strcmp(*reserved
, value
) == 0)
682 void CYSwitch::Output(CYOutput
&out
, CYFlags flags
) const {
683 out
<< "switch" << ' ' << '(' << *value_
<< ')' << ' ' << '{';
688 void CYThis::Output(CYOutput
&out
, CYFlags flags
) const {
695 void Throw::Output(CYOutput
&out
, CYFlags flags
) const {
698 out
<< ' ' << *value_
;
702 void Try::Output(CYOutput
&out
, CYFlags flags
) const {
703 out
<< "try" << ' ' << code_
<< catch_
<< finally_
;
708 void CYVar::Output(CYOutput
&out
, CYFlags flags
) const {
710 declarations_
->Output(out
, flags
);
714 void CYVariable::Output(CYOutput
&out
, CYFlags flags
) const {
718 void CYWhile::Output(CYOutput
&out
, CYFlags flags
) const {
719 out
<< "while" << '(' << *test_
<< ')';
720 code_
->Single(out
, CYRight(flags
));
723 void CYWith::Output(CYOutput
&out
, CYFlags flags
) const {
724 out
<< "with" << '(' << *scope_
<< ')';
725 code_
->Single(out
, CYRight(flags
));
728 void CYWord::ClassName(CYOutput
&out
, bool object
) const {
730 out
<< "objc_getClass(";
731 out
<< '"' << Word() << '"';
736 void CYWord::Output(CYOutput
&out
) const {
738 if (out
.options_
.verbose_
)
739 out
.out_
<< '@' << this;
742 void CYWord::PropertyName(CYOutput
&out
) const {
746 const char *CYWord::Word() const {