]>
git.saurik.com Git - cycript.git/blob - Output.cpp
   1 /* Cycript - Optimizing JavaScript Compiler/Runtime 
   2  * Copyright (C) 2009-2013  Jay Freeman (saurik) 
   5 /* GNU General Public License, Version 3 {{{ */ 
   7  * Cycript is free software: you can redistribute it and/or modify 
   8  * it under the terms of the GNU General Public License as published 
   9  * by the Free Software Foundation, either version 3 of the License, 
  10  * or (at your option) any later version. 
  12  * Cycript is distributed in the hope that it will be useful, but 
  13  * WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  * GNU General Public License for more details. 
  17  * You should have received a copy of the GNU General Public License 
  18  * along with Cycript.  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     if (WordEndRange_
[rhs
[size 
- 1]]) 
 112 void CYArgument::Output(CYOutput 
&out
) const { 
 119         value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 122         out 
<< ' ' << *next_
; 
 126 void CYArray::Output(CYOutput 
&out
, CYFlags flags
) const { 
 127     out 
<< '[' << elements_ 
<< ']'; 
 130 void CYArrayComprehension::Output(CYOutput 
&out
, CYFlags flags
) const { 
 131     out 
<< '[' << *expression_ 
<< ' ' << *comprehensions_ 
<< ']'; 
 134 void CYAssignment::Output(CYOutput 
&out
, CYFlags flags
) const { 
 135     lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
); 
 136     out 
<< ' ' << Operator() << ' '; 
 137     rhs_
->Output(out
, Precedence(), CYRight(flags
)); 
 140 void CYBlock::Output(CYOutput 
&out
) const { 
 143     if (statements_ 
!= NULL
) 
 144         statements_
->Multiple(out
); 
 149 void CYBlock::Output(CYOutput 
&out
, CYFlags flags
) const { 
 150     if (statements_ 
== NULL
) 
 152     else if (statements_
->next_ 
== NULL
) 
 153         statements_
->Single(out
, flags
); 
 158 void CYBoolean::Output(CYOutput 
&out
, CYFlags flags
) const { 
 159     out 
<< (Value() ? "true" : "false"); 
 162 void CYBreak::Output(CYOutput 
&out
, CYFlags flags
) const { 
 165         out 
<< ' ' << *label_
; 
 169 void CYCall::Output(CYOutput 
&out
, CYFlags flags
) const { 
 170     bool protect((flags 
& CYNoCall
) != 0); 
 173     function_
->Output(out
, Precedence(), protect 
? CYNoFlags 
: flags
); 
 174     out 
<< '(' << arguments_ 
<< ')'; 
 182 void Catch::Output(CYOutput 
&out
) const { 
 183     out 
<< ' ' << "catch" << ' ' << '(' << *name_ 
<< ')' << ' ' << code_
; 
 188 void CYComment::Output(CYOutput 
&out
, CYFlags flags
) const { 
 195 void CYCompound::Output(CYOutput 
&out
, CYFlags flags
) const { 
 197         expression_
->Output(out
, flags
); 
 199         expression_
->Output(out
, CYLeft(flags
)); 
 201         next_
->Output(out
, CYRight(flags
)); 
 205 void CYCondition::Output(CYOutput 
&out
, CYFlags flags
) const { 
 206     test_
->Output(out
, Precedence() - 1, CYLeft(flags
)); 
 207     out 
<< ' ' << '?' << ' '; 
 209         true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 210     out 
<< ' ' << ':' << ' '; 
 211     false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
)); 
 214 void CYContinue::Output(CYOutput 
&out
, CYFlags flags
) const { 
 217         out 
<< ' ' << *label_
; 
 221 void CYClause::Output(CYOutput 
&out
) const { 
 223         out 
<< "case" << ' ' << *case_
; 
 227     if (statements_ 
!= NULL
) 
 228         statements_
->Multiple(out
); 
 232 void CYDebugger::Output(CYOutput 
&out
, CYFlags flags
) const { 
 233     out 
<< "debugger" << ';'; 
 236 void CYDeclaration::ForIn(CYOutput 
&out
, CYFlags flags
) const { 
 238     Output(out
, CYRight(flags
)); 
 241 void CYDeclaration::Output(CYOutput 
&out
, CYFlags flags
) const { 
 243     //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_; 
 244     if (initialiser_ 
!= NULL
) { 
 245         out 
<< ' ' << '=' << ' '; 
 246         initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
)); 
 250 void CYForDeclarations::Output(CYOutput 
&out
, CYFlags flags
) const { 
 252     Output(out
, CYRight(flags
)); 
 255 void CYDeclarations::Output(CYOutput 
&out
) const { 
 256     Output(out
, CYNoFlags
); 
 259 void CYDeclarations::Output(CYOutput 
&out
, CYFlags flags
) const { 
 260     const CYDeclarations 
*declaration(this); 
 264         CYDeclarations 
*next(declaration
->next_
); 
 266         CYFlags 
jacks(first 
? CYLeft(flags
) : next 
== NULL 
? CYRight(flags
) : CYCenter(flags
)); 
 268         declaration
->declaration_
->Output(out
, jacks
); 
 278 void CYDirectMember::Output(CYOutput 
&out
, CYFlags flags
) const { 
 279     object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
); 
 280     if (const char *word 
= property_
->Word()) 
 283         out 
<< '[' << *property_ 
<< ']'; 
 286 void CYDoWhile::Output(CYOutput 
&out
, CYFlags flags
) const { 
 288     code_
->Single(out
, CYCenter(flags
)); 
 289     out 
<< "while" << ' ' << '(' << *test_ 
<< ')'; 
 292 void CYElement::Output(CYOutput 
&out
) const { 
 294         value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 295     if (next_ 
!= NULL 
|| value_ 
== NULL
) { 
 297         if (next_ 
!= NULL 
&& next_
->value_ 
!= NULL
) 
 304 void CYEmpty::Output(CYOutput 
&out
, CYFlags flags
) const { 
 308 void CYExpress::Output(CYOutput 
&out
, CYFlags flags
) const { 
 309     expression_
->Output(out
, flags 
| CYNoBF
); 
 313 void CYExpression::ClassName(CYOutput 
&out
, bool object
) const { 
 314     Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 317 void CYExpression::ForIn(CYOutput 
&out
, CYFlags flags
) const { 
 318     Output(out
, flags 
| CYNoRightHand
); 
 321 void CYExpression::Output(CYOutput 
&out
) const { 
 322     Output(out
, CYNoFlags
); 
 325 void CYExpression::Output(CYOutput 
&out
, int precedence
, CYFlags flags
) const { 
 326     if (precedence 
< Precedence() || (flags 
& CYNoRightHand
) != 0 && RightHand()) 
 327         out 
<< '(' << *this << ')'; 
 332 void CYFatArrow::Output(CYOutput 
&out
, CYFlags flags
) const { 
 333     out 
<< '(' << parameters_ 
<< ')' << ' ' << "=>" << ' ' << code_
; 
 336 void CYFinally::Output(CYOutput 
&out
) const { 
 337     out 
<< ' ' << "finally" << ' ' << code_
; 
 340 void CYFor::Output(CYOutput 
&out
, CYFlags flags
) const { 
 341     out 
<< "for" << ' ' << '('; 
 342     if (initialiser_ 
!= NULL
) 
 343         initialiser_
->Output(out
, CYNoIn
); 
 349     if (increment_ 
!= NULL
) 
 353     code_
->Single(out
, CYRight(flags
)); 
 356 void CYForOf::Output(CYOutput 
&out
, CYFlags flags
) const { 
 357     out 
<< "for" << ' ' << "each" << ' ' << '('; 
 358     initialiser_
->ForIn(out
, CYNoIn
); 
 359     out 
<< "in" << *set_ 
<< ')'; 
 360     code_
->Single(out
, CYRight(flags
)); 
 363 void CYForOfComprehension::Output(CYOutput 
&out
) const { 
 364     out 
<< "for" << ' ' << "each" << ' ' << '(' << *name_ 
<< ' ' << "in" << ' ' << *set_ 
<< ')' << next_
; 
 367 void CYForIn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 368     out 
<< "for" << ' ' << '('; 
 369     if (initialiser_ 
!= NULL
) 
 370         initialiser_
->ForIn(out
, CYNoIn
); 
 371     out 
<< "in" << *set_ 
<< ')'; 
 372     code_
->Single(out
, CYRight(flags
)); 
 375 void CYForInComprehension::Output(CYOutput 
&out
) const { 
 376     out 
<< "for" << ' ' << '(' << *name_ 
<< ' ' << "in" << ' ' << *set_ 
<< ')'; 
 379 void CYFunction::Output(CYOutput 
&out
, CYFlags flags
) const { 
 380     // XXX: one could imagine using + here to save a byte 
 381     bool protect((flags 
& CYNoFunction
) != 0); 
 386         out 
<< ' ' << *name_
; 
 387     out 
<< '(' << parameters_ 
<< ')'; 
 393 void CYFunctionExpression::Output(CYOutput 
&out
, CYFlags flags
) const { 
 394     CYFunction::Output(out
, flags
); 
 397 void CYFunctionStatement::Output(CYOutput 
&out
, CYFlags flags
) const { 
 398     CYFunction::Output(out
, flags
); 
 401 void CYFunctionParameter::Output(CYOutput 
&out
) const { 
 402     initialiser_
->Output(out
, CYNoFlags
); 
 404         out 
<< ',' << ' ' << *next_
; 
 407 const char *CYIdentifier::Word() const { 
 408     return replace_ 
== NULL 
|| replace_ 
== this ? CYWord::Word() : replace_
->Word(); 
 411 void CYIf::Output(CYOutput 
&out
, CYFlags flags
) const { 
 413     if (false_ 
== NULL 
&& (flags 
& CYNoDangle
) != 0) { 
 418     out 
<< "if" << ' ' << '(' << *test_ 
<< ')'; 
 420     CYFlags 
right(protect 
? CYNoFlags 
: CYRight(flags
)); 
 422     CYFlags 
jacks(CYNoDangle
); 
 426         jacks 
|= protect 
? CYNoFlags 
: CYCenter(flags
); 
 428     true_
->Single(out
, jacks
); 
 430     if (false_ 
!= NULL
) { 
 431         out 
<< '\t' << "else"; 
 432         false_
->Single(out
, right
); 
 439 void CYIfComprehension::Output(CYOutput 
&out
) const { 
 440     out 
<< "if" << ' ' << '(' << *test_ 
<< ')' << next_
; 
 443 void CYIndirectMember::Output(CYOutput 
&out
, CYFlags flags
) const { 
 444     object_
->Output(out
, Precedence(), CYLeft(flags
)); 
 445     if (const char *word 
= property_
->Word()) 
 448         out 
<< "->" << '[' << *property_ 
<< ']'; 
 451 void CYInfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 452     const char *name(Operator()); 
 453     bool protect((flags 
& CYNoIn
) != 0 && strcmp(name
, "in") == 0); 
 456     CYFlags 
left(protect 
? CYNoFlags 
: CYLeft(flags
)); 
 457     lhs_
->Output(out
, Precedence(), left
); 
 458     out 
<< ' ' << name 
<< ' '; 
 459     CYFlags 
right(protect 
? CYNoFlags 
: CYRight(flags
)); 
 460     rhs_
->Output(out
, Precedence() - 1, right
); 
 465 void CYLabel::Output(CYOutput 
&out
, CYFlags flags
) const { 
 466     out 
<< *name_ 
<< ':' << ' '; 
 467     statement_
->Single(out
, CYRight(flags
)); 
 470 void CYTypeArrayOf::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 471     next_
->Output(out
, Precedence(), identifier
); 
 477 void CYTypeBlockWith::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 479     next_
->Output(out
, Precedence(), identifier
); 
 480     out 
<< ')' << '(' << parameters_ 
<< ')'; 
 483 void CYTypeConstant::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 485     next_
->Output(out
, Precedence(), identifier
); 
 488 void CYTypeFunctionWith::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 489     next_
->Output(out
, Precedence(), identifier
); 
 490     out 
<< '(' << parameters_ 
<< ')'; 
 493 void CYTypePointerTo::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 495     next_
->Output(out
, Precedence(), identifier
); 
 498 void CYTypeVolatile::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 500     next_
->Output(out
, Precedence(), identifier
); 
 503 void CYTypeModifier::Output(CYOutput 
&out
, int precedence
, CYIdentifier 
*identifier
) const { 
 509     bool protect(precedence 
> Precedence()); 
 513     Output(out
, identifier
); 
 518 void CYTypedIdentifier::Output(CYOutput 
&out
) const { 
 519     specifier_
->Output(out
); 
 520     modifier_
->Output(out
, 0, identifier_
); 
 523 void CYEncodedType::Output(CYOutput 
&out
, CYFlags flags
) const { 
 524     out 
<< "@encode(" << typed_ 
<< ")"; 
 527 void CYTypedParameter::Output(CYOutput 
&out
) const { 
 530         out 
<< ',' << ' ' << next_
; 
 533 void CYLambda::Output(CYOutput 
&out
, CYFlags flags
) const { 
 534     // XXX: this is seriously wrong 
 541 void CYTypeDefinition::Output(CYOutput 
&out
, CYFlags flags
) const { 
 542     out 
<< "typedef" << *typed_
; 
 545 void CYLetStatement::Output(CYOutput 
&out
, CYFlags flags
) const { 
 546     out 
<< "let" << ' ' << '(' << *declarations_ 
<< ')'; 
 547     code_
->Single(out
, CYRight(flags
)); 
 553 void New::Output(CYOutput 
&out
, CYFlags flags
) const { 
 555     CYFlags 
jacks(CYNoCall 
| CYCenter(flags
)); 
 556     constructor_
->Output(out
, Precedence(), jacks
); 
 557     if (arguments_ 
!= NULL
) 
 558         out 
<< '(' << *arguments_ 
<< ')'; 
 563 void CYNull::Output(CYOutput 
&out
, CYFlags flags
) const { 
 567 void CYNumber::Output(CYOutput 
&out
, CYFlags flags
) const { 
 568     std::ostringstream str
; 
 569     CYNumerify(str
, Value()); 
 570     std::string 
value(str
.str()); 
 571     out 
<< value
.c_str(); 
 572     // XXX: this should probably also handle hex conversions and exponents 
 573     if ((flags 
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
) 
 577 void CYNumber::PropertyName(CYOutput 
&out
) const { 
 578     Output(out
, CYNoFlags
); 
 581 void CYObject::Output(CYOutput 
&out
, CYFlags flags
) const { 
 582     bool protect((flags 
& CYNoBrace
) != 0); 
 594 void CYPostfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 595     lhs_
->Output(out
, Precedence(), CYLeft(flags
)); 
 599 void CYPrefix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 600     const char *name(Operator()); 
 604     rhs_
->Output(out
, Precedence(), CYRight(flags
)); 
 607 void CYProgram::Output(CYOutput 
&out
) const { 
 608     if (statements_ 
!= NULL
) 
 609         statements_
->Multiple(out
); 
 612 void CYProperty::Output(CYOutput 
&out
) const { 
 614     name_
->PropertyName(out
); 
 616     value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 618         out 
<< ',' << '\n' << *next_
; 
 623 void CYRegEx::Output(CYOutput 
&out
, CYFlags flags
) const { 
 627 void CYReturn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 630         out 
<< ' ' << *value_
; 
 634 void CYRubyBlock::Output(CYOutput 
&out
, CYFlags flags
) const { 
 635     call_
->Output(out
, CYLeft(flags
)); 
 637     proc_
->Output(out
, CYRight(flags
)); 
 640 void CYRubyProc::Output(CYOutput 
&out
, CYFlags flags
) const { 
 641     // XXX: this is not outputting the parameters 
 645 void CYStatement::Multiple(CYOutput 
&out
, CYFlags flags
) const { 
 647     CYForEach (next
, this) { 
 648         bool last(next
->next_ 
== NULL
); 
 649         CYFlags 
jacks(first 
? last 
? flags 
: CYLeft(flags
) : last 
? CYRight(flags
) : CYCenter(flags
)); 
 652         next
->Output(out
, jacks
); 
 657 void CYStatement::Single(CYOutput 
&out
, CYFlags flags
) const { 
 659         return out
.Terminate(); 
 661     _assert(next_ 
== NULL
); 
 670 void CYString::Output(CYOutput 
&out
, CYFlags flags
) const { 
 671     std::ostringstream str
; 
 672     CYStringify(str
, value_
, size_
); 
 673     out 
<< str
.str().c_str(); 
 676 void CYString::PropertyName(CYOutput 
&out
) const { 
 677     if (const char *word 
= Word()) 
 683 static const char *Reserved_
[] = { 
 684     "false", "null", "true", 
 686     "break", "case", "catch", "continue", "default", 
 687     "delete", "do", "else", "finally", "for", "function", 
 688     "if", "in", "instanceof", "new", "return", "switch", 
 689     "this", "throw", "try", "typeof", "var", "void", 
 694     "class", "enum", "export", "extends", "import", "super", 
 696     "abstract", "boolean", "byte", "char", "double", "final", 
 697     "float", "goto", "int", "long", "native", "short", 
 698     "synchronized", "throws", "transient", "volatile", 
 705 const char *CYString::Word() const { 
 706     if (size_ 
== 0 || !WordStartRange_
[value_
[0]]) 
 708     for (size_t i(1); i 
!= size_
; ++i
) 
 709         if (!WordEndRange_
[value_
[i
]]) 
 711     const char *value(Value()); 
 712     for (const char **reserved(Reserved_
); *reserved 
!= NULL
; ++reserved
) 
 713         if (strcmp(*reserved
, value
) == 0) 
 718 void CYSwitch::Output(CYOutput 
&out
, CYFlags flags
) const { 
 719     out 
<< "switch" << ' ' << '(' << *value_ 
<< ')' << ' ' << '{'; 
 724 void CYThis::Output(CYOutput 
&out
, CYFlags flags
) const { 
 731 void Throw::Output(CYOutput 
&out
, CYFlags flags
) const { 
 734         out 
<< ' ' << *value_
; 
 738 void Try::Output(CYOutput 
&out
, CYFlags flags
) const { 
 739     out 
<< "try" << ' ' << code_ 
<< catch_ 
<< finally_
; 
 744 void CYTypeError::Output(CYOutput 
&out
) const { 
 748 void CYTypeLong::Output(CYOutput 
&out
) const { 
 749     out 
<< "long" << specifier_
; 
 752 void CYTypeShort::Output(CYOutput 
&out
) const { 
 753     out 
<< "short" << specifier_
; 
 756 void CYTypeSigned::Output(CYOutput 
&out
) const { 
 757     out 
<< "signed" << specifier_
; 
 760 void CYTypeUnsigned::Output(CYOutput 
&out
) const { 
 761     out 
<< "unsigned" << specifier_
; 
 764 void CYTypeVariable::Output(CYOutput 
&out
) const { 
 768 void CYTypeVoid::Output(CYOutput 
&out
) const { 
 772 void CYVar::Output(CYOutput 
&out
, CYFlags flags
) const { 
 774     declarations_
->Output(out
, flags
); 
 778 void CYVariable::Output(CYOutput 
&out
, CYFlags flags
) const { 
 782 void CYWhile::Output(CYOutput 
&out
, CYFlags flags
) const { 
 783     out 
<< "while" << '(' << *test_ 
<< ')'; 
 784     code_
->Single(out
, CYRight(flags
)); 
 787 void CYWith::Output(CYOutput 
&out
, CYFlags flags
) const { 
 788     out 
<< "with" << '(' << *scope_ 
<< ')'; 
 789     code_
->Single(out
, CYRight(flags
)); 
 792 void CYWord::ClassName(CYOutput 
&out
, bool object
) const { 
 794         out 
<< "objc_getClass("; 
 795     out 
<< '"' << Word() << '"'; 
 800 void CYWord::Output(CYOutput 
&out
) const { 
 802     if (out
.options_
.verbose_
) 
 803         out
.out_ 
<< '@' << this; 
 806 void CYWord::PropertyName(CYOutput 
&out
) const { 
 810 const char *CYWord::Word() const {