]>
git.saurik.com Git - cycript.git/blob - Output.cpp
8b77e0ef4c763c749a0782b6848da3323fe8c06b
   1 /* Cycript - Inlining/Optimizing JavaScript Compiler 
   2  * Copyright (C) 2009  Jay Freeman (saurik) 
   5 /* Modified BSD License {{{ */ 
   7  *        Redistribution and use in source and binary 
   8  * forms, with or without modification, are permitted 
   9  * provided that the following conditions are met: 
  11  * 1. Redistributions of source code must retain the 
  12  *    above copyright notice, this list of conditions 
  13  *    and the following disclaimer. 
  14  * 2. Redistributions in binary form must reproduce the 
  15  *    above copyright notice, this list of conditions 
  16  *    and the following disclaimer in the documentation 
  17  *    and/or other materials provided with the 
  19  * 3. The name of the author may not be used to endorse 
  20  *    or promote products derived from this software 
  21  *    without specific prior written permission. 
  23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' 
  24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
  25  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
  26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  27  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 
  28  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
  30  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
  31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
  33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
  34  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
  35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
  36  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  40 #include "cycript.hpp" 
  45 _finline CYFlags 
operator ~(CYFlags rhs
) { 
  46     return static_cast<CYFlags
>(~static_cast<unsigned>(rhs
)); 
  49 _finline CYFlags 
operator &(CYFlags lhs
, CYFlags rhs
) { 
  50     return static_cast<CYFlags
>(static_cast<unsigned>(lhs
) & static_cast<unsigned>(rhs
)); 
  53 _finline CYFlags 
operator |(CYFlags lhs
, CYFlags rhs
) { 
  54     return static_cast<CYFlags
>(static_cast<unsigned>(lhs
) | static_cast<unsigned>(rhs
)); 
  57 _finline CYFlags 
&operator |=(CYFlags 
&lhs
, CYFlags rhs
) { 
  58     return lhs 
= lhs 
| rhs
; 
  61 _finline CYFlags 
CYLeft(CYFlags flags
) { 
  62     return flags 
& ~(CYNoDangle 
| CYNoInteger
); 
  65 _finline CYFlags 
CYRight(CYFlags flags
) { 
  66     return flags 
& ~CYNoBF
; 
  69 _finline CYFlags 
CYCenter(CYFlags flags
) { 
  70     return CYLeft(CYRight(flags
)); 
  73 void CYOutput::Terminate() { 
  78 CYOutput 
&CYOutput::operator <<(char rhs
) { 
  79     if (rhs 
== ' ' || rhs 
== '\n') 
  85             for (unsigned i(0); i 
!= indent_
; ++i
) 
  88     else if (rhs 
== '\r') { 
 100     if (mode_ 
== Terminated 
&& rhs 
!= '}') { 
 112     } else if (rhs 
== '+') { 
 116     } else if (rhs 
== '-') { 
 117         if (mode_ 
== NoHyphen
) 
 120     } else if (WordEndRange_
[rhs
]) { 
 121         if (mode_ 
== NoLetter
) 
 133 CYOutput 
&CYOutput::operator <<(const char *rhs
) { 
 134     size_t size(strlen(rhs
)); 
 137         return *this << *rhs
; 
 139     if (mode_ 
== Terminated
) 
 142         mode_ 
== NoPlus 
&& *rhs 
== '+' || 
 143         mode_ 
== NoHyphen 
&& *rhs 
== '-' || 
 144         mode_ 
== NoLetter 
&& WordEndRange_
[*rhs
] 
 148     if (WordEndRange_
[rhs
[size 
- 1]]) 
 158 void CYArgument::Output(CYOutput 
&out
) const { 
 165         value_
->Output(out
, CYPA
, CYNoFlags
); 
 167         if (next_
->name_ 
== NULL
) 
 169         out 
<< ' ' << *next_
; 
 173 void CYArray::Output(CYOutput 
&out
, CYFlags flags
) const { 
 174     out 
<< '[' << elements_ 
<< ']'; 
 177 void CYArrayComprehension::Output(CYOutput 
&out
, CYFlags flags
) const { 
 178     out 
<< '[' << *expression_ 
<< ' ' << *comprehensions_ 
<< ']'; 
 181 void CYAssignment::Output(CYOutput 
&out
, CYFlags flags
) const { 
 182     lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
); 
 183     out 
<< ' ' << Operator() << ' '; 
 184     rhs_
->Output(out
, Precedence(), CYRight(flags
)); 
 187 void CYBlock::Output(CYOutput 
&out
) const { 
 190     if (statements_ 
!= NULL
) 
 191         statements_
->Multiple(out
); 
 196 void CYBlock::Output(CYOutput 
&out
, CYFlags flags
) const { 
 197     if (statements_ 
== NULL
) 
 199     else if (statements_
->next_ 
== NULL
) 
 200         statements_
->Single(out
, flags
); 
 205 void CYBoolean::Output(CYOutput 
&out
, CYFlags flags
) const { 
 206     out 
<< (Value() ? "true" : "false"); 
 209 void CYBreak::Output(CYOutput 
&out
, CYFlags flags
) const { 
 212         out 
<< ' ' << *label_
; 
 216 void CYCall::Output(CYOutput 
&out
, CYFlags flags
) const { 
 217     bool protect((flags 
& CYNoCall
) != 0); 
 220     function_
->Output(out
, Precedence(), protect 
? CYNoFlags 
: flags
); 
 221     out 
<< '(' << arguments_ 
<< ')'; 
 229 void Catch::Output(CYOutput 
&out
) const { 
 230     out 
<< ' ' << "catch" << ' ' << '(' << *name_ 
<< ')' << ' ' << code_
; 
 235 void CYComment::Output(CYOutput 
&out
, CYFlags flags
) const { 
 242 void CYCompound::Output(CYOutput 
&out
, CYFlags flags
) const { 
 243     if (CYExpression 
*expression 
= expressions_
) 
 244         if (CYExpression 
*next 
= expression
->next_
) { 
 245             expression
->Output(out
, CYLeft(flags
)); 
 246             CYFlags 
center(CYCenter(flags
)); 
 247             while (next 
!= NULL
) { 
 250                 next 
= expression
->next_
; 
 251                 CYFlags 
right(next 
!= NULL 
? center 
: CYRight(flags
)); 
 252                 expression
->Output(out
, right
); 
 255             expression
->Output(out
, flags
); 
 258 void CYCondition::Output(CYOutput 
&out
, CYFlags flags
) const { 
 259     test_
->Output(out
, Precedence() - 1, CYLeft(flags
)); 
 260     out 
<< ' ' << '?' << ' '; 
 262         true_
->Output(out
, CYPA
, CYNoFlags
); 
 263     out 
<< ' ' << ':' << ' '; 
 264     false_
->Output(out
, CYPA
, CYRight(flags
)); 
 267 void CYContinue::Output(CYOutput 
&out
, CYFlags flags
) const { 
 270         out 
<< ' ' << *label_
; 
 274 void CYClause::Output(CYOutput 
&out
) const { 
 276         out 
<< "case" << ' ' << *case_
; 
 280     if (statements_ 
!= NULL
) 
 281         statements_
->Multiple(out
); 
 285 const char *CYDeclaration::ForEachIn() const { 
 286     return identifier_
->Word(); 
 289 void CYDeclaration::ForIn(CYOutput 
&out
, CYFlags flags
) const { 
 291     Output(out
, CYRight(flags
)); 
 294 void CYDeclaration::Output(CYOutput 
&out
, CYFlags flags
) const { 
 296     //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_; 
 297     if (initialiser_ 
!= NULL
) { 
 298         out 
<< ' ' << '=' << ' '; 
 299         initialiser_
->Output(out
, CYPA
, CYRight(flags
)); 
 303 void CYDeclarations::For(CYOutput 
&out
) const { 
 308 void CYDeclarations::Output(CYOutput 
&out
) const { 
 309     Output(out
, CYNoFlags
); 
 312 void CYDeclarations::Output(CYOutput 
&out
, CYFlags flags
) const { 
 313     const CYDeclarations 
*declaration(this); 
 316     CYDeclarations 
*next(declaration
->next_
); 
 317     CYFlags 
jacks(first 
? CYLeft(flags
) : next 
== NULL 
? CYRight(flags
) : CYCenter(flags
)); 
 319     declaration
->declaration_
->Output(out
, jacks
); 
 328 void CYDirectMember::Output(CYOutput 
&out
, CYFlags flags
) const { 
 329     object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
); 
 330     if (const char *word 
= property_
->Word()) 
 333         out 
<< '[' << *property_ 
<< ']'; 
 336 void CYDoWhile::Output(CYOutput 
&out
, CYFlags flags
) const { 
 338     code_
->Single(out
, CYCenter(flags
)); 
 339     out 
<< "while" << ' ' << '(' << *test_ 
<< ')'; 
 342 void CYElement::Output(CYOutput 
&out
) const { 
 344         value_
->Output(out
, CYPA
, CYNoFlags
); 
 345     if (next_ 
!= NULL 
|| value_ 
== NULL
) { 
 347         if (next_ 
!= NULL 
&& next_
->value_ 
!= NULL
) 
 354 void CYEmpty::Output(CYOutput 
&out
, CYFlags flags
) const { 
 358 void CYExpress::Output(CYOutput 
&out
, CYFlags flags
) const { 
 359     expression_
->Output(out
, flags 
| CYNoBF
); 
 363 void CYExpression::ClassName(CYOutput 
&out
, bool object
) const { 
 364     Output(out
, CYPA
, CYNoFlags
); 
 367 const char *CYExpression::ForEachIn() const { 
 371 void CYExpression::For(CYOutput 
&out
) const { 
 375 void CYExpression::ForIn(CYOutput 
&out
, CYFlags flags
) const { 
 376     Output(out
, flags 
| CYNoRightHand
); 
 379 void CYExpression::Output(CYOutput 
&out
) const { 
 380     Output(out
, CYNoFlags
); 
 383 void CYExpression::Output(CYOutput 
&out
, unsigned precedence
, CYFlags flags
) const { 
 384     if (precedence 
< Precedence() || (flags 
& CYNoRightHand
) != 0 && RightHand()) 
 385         out 
<< '(' << *this << ')'; 
 390 void CYFinally::Output(CYOutput 
&out
) const { 
 391     out 
<< ' ' << "finally" << ' ' << code_
; 
 394 void CYFor::Output(CYOutput 
&out
, CYFlags flags
) const { 
 395     out 
<< "for" << ' ' << '('; 
 396     if (initialiser_ 
!= NULL
) 
 397         initialiser_
->For(out
); 
 403     code_
->Single(out
, CYRight(flags
)); 
 406 void CYForEachIn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 407     out 
<< "for" << ' ' << "each" << ' ' << '('; 
 408     initialiser_
->ForIn(out
, CYNoIn
); 
 409     out 
<< "in" << *set_ 
<< ')'; 
 410     code_
->Single(out
, CYRight(flags
)); 
 413 void CYForEachInComprehension::Output(CYOutput 
&out
) const { 
 414     out 
<< "for" << ' ' << "each" << ' ' << '(' << *name_ 
<< ' ' << "in" << ' ' << *set_ 
<< ')' << next_
; 
 417 void CYForIn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 418     out 
<< "for" << ' ' << '('; 
 419     if (initialiser_ 
!= NULL
) 
 420         initialiser_
->ForIn(out
, CYNoIn
); 
 421     out 
<< "in" << *set_ 
<< ')'; 
 422     code_
->Single(out
, CYRight(flags
)); 
 425 void CYForInComprehension::Output(CYOutput 
&out
) const { 
 426     out 
<< "for" << ' ' << '(' << *name_ 
<< ' ' << "in" << ' ' << *set_ 
<< ')'; 
 429 void CYFunction::Output(CYOutput 
&out
, CYFlags flags
) const { 
 430     // XXX: one could imagine using + here to save a byte 
 431     bool protect((flags 
& CYNoFunction
) != 0); 
 436         out 
<< ' ' << *name_
; 
 437     out 
<< '(' << parameters_ 
<< ')'; 
 443 void CYFunctionExpression::Output(CYOutput 
&out
, CYFlags flags
) const { 
 444     CYFunction::Output(out
, flags
); 
 447 void CYFunctionStatement::Output(CYOutput 
&out
, CYFlags flags
) const { 
 448     CYFunction::Output(out
, flags
); 
 451 void CYFunctionParameter::Output(CYOutput 
&out
) const { 
 454         out 
<< ',' << ' ' << *next_
; 
 457 const char *CYIdentifier::Word() const { 
 458     return replace_ 
== NULL 
|| replace_ 
== this ? CYWord::Word() : replace_
->Word(); 
 461 void CYIf::Output(CYOutput 
&out
, CYFlags flags
) const { 
 463     if (false_ 
== NULL 
&& (flags 
& CYNoDangle
) != 0) { 
 468     out 
<< "if" << ' ' << '(' << *test_ 
<< ')'; 
 470     CYFlags 
right(protect 
? CYNoFlags 
: CYRight(flags
)); 
 472     CYFlags 
jacks(CYNoDangle
); 
 476         jacks 
|= protect 
? CYNoFlags 
: CYCenter(flags
); 
 478     true_
->Single(out
, jacks
); 
 480     if (false_ 
!= NULL
) { 
 482         false_
->Single(out
, right
); 
 489 void CYIfComprehension::Output(CYOutput 
&out
) const { 
 490     out 
<< "if" << ' ' << '(' << *test_ 
<< ')' << next_
; 
 493 void CYIndirectMember::Output(CYOutput 
&out
, CYFlags flags
) const { 
 494     object_
->Output(out
, Precedence(), CYLeft(flags
)); 
 495     if (const char *word 
= property_
->Word()) 
 498         out 
<< "->" << '[' << *property_ 
<< ']'; 
 501 void CYInfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 502     const char *name(Operator()); 
 503     bool protect((flags 
& CYNoIn
) != 0 && strcmp(name
, "in") == 0); 
 506     CYFlags 
left(protect 
? CYNoFlags 
: CYLeft(flags
)); 
 507     lhs_
->Output(out
, Precedence(), left
); 
 508     out 
<< ' ' << name 
<< ' '; 
 509     CYFlags 
right(protect 
? CYNoFlags 
: CYRight(flags
)); 
 510     rhs_
->Output(out
, Precedence() - 1, right
); 
 515 void CYLabel::Output(CYOutput 
&out
, CYFlags flags
) const { 
 516     out 
<< *name_ 
<< ':' << ' '; 
 517     statement_
->Single(out
, CYRight(flags
)); 
 520 void CYLet::Output(CYOutput 
&out
, CYFlags flags
) const { 
 521     out 
<< "let" << ' ' << '(' << *declarations_ 
<< ')' << ' ' << code_
; 
 524 void CYNew::Output(CYOutput 
&out
, CYFlags flags
) const { 
 526     CYFlags 
jacks(CYNoCall 
| CYCenter(flags
)); 
 527     constructor_
->Output(out
, Precedence(), jacks
); 
 528     if (arguments_ 
!= NULL
) 
 529         out 
<< '(' << *arguments_ 
<< ')'; 
 532 void CYNull::Output(CYOutput 
&out
, CYFlags flags
) const { 
 536 void CYNumber::Output(CYOutput 
&out
, CYFlags flags
) const { 
 537     std::ostringstream str
; 
 538     CYNumerify(str
, Value()); 
 539     std::string 
value(str
.str()); 
 540     out 
<< value
.c_str(); 
 541     // XXX: this should probably also handle hex conversions and exponents 
 542     if ((flags 
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
) 
 546 void CYNumber::PropertyName(CYOutput 
&out
) const { 
 547     Output(out
, CYNoFlags
); 
 550 void CYObject::Output(CYOutput 
&out
, CYFlags flags
) const { 
 551     bool protect((flags 
& CYNoBrace
) != 0); 
 563 void CYOptionalFunctionParameter::Output(CYOutput 
&out
) const { 
 564     out 
<< *name_ 
<< '=' << *initializer_
; 
 566         out 
<< ',' << ' ' << *next_
; 
 569 void CYPostfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 570     lhs_
->Output(out
, Precedence(), CYLeft(flags
)); 
 574 void CYPrefix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 575     const char *name(Operator()); 
 579     rhs_
->Output(out
, Precedence(), CYRight(flags
)); 
 582 void CYProgram::Output(CYOutput 
&out
) const { 
 583     if (statements_ 
!= NULL
) 
 584         statements_
->Multiple(out
); 
 587 void CYProperty::Output(CYOutput 
&out
) const { 
 589     name_
->PropertyName(out
); 
 591     value_
->Output(out
, CYPA
, CYNoFlags
); 
 593         out 
<< ',' << '\n' << *next_
; 
 598 void CYRegEx::Output(CYOutput 
&out
, CYFlags flags
) const { 
 602 void CYReturn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 605         out 
<< ' ' << *value_
; 
 609 void CYStatement::Multiple(CYOutput 
&out
, CYFlags flags
) const { 
 611     for (const CYStatement 
*next(this); next 
!= NULL
; next 
= next
->next_
) { 
 612         bool last(next
->next_ 
== NULL
); 
 613         CYFlags 
jacks(first 
? last 
? flags 
: CYLeft(flags
) : last 
? CYCenter(flags
) : CYRight(flags
)); 
 616         next
->Output(out
, jacks
); 
 621 void CYStatement::Single(CYOutput 
&out
, CYFlags flags
) const { 
 622     _assert(next_ 
== NULL
); 
 631 void CYString::Output(CYOutput 
&out
, CYFlags flags
) const { 
 632     std::ostringstream str
; 
 633     CYStringify(str
, value_
, size_
); 
 634     out 
<< str
.str().c_str(); 
 637 void CYString::PropertyName(CYOutput 
&out
) const { 
 638     if (const char *word 
= Word()) 
 644 static const char *Reserved_
[] = { 
 645     "false", "null", "true", 
 647     "break", "case", "catch", "continue", "default", 
 648     "delete", "do", "else", "finally", "for", "function", 
 649     "if", "in", "instanceof", "new", "return", "switch", 
 650     "this", "throw", "try", "typeof", "var", "void", 
 655     "class", "enum", "export", "extends", "import", "super", 
 657     "abstract", "boolean", "byte", "char", "double", "final", 
 658     "float", "goto", "int", "long", "native", "short", 
 659     "synchronized", "throws", "transient", "volatile", 
 666 const char *CYString::Word() const { 
 667     if (size_ 
== 0 || !WordStartRange_
[value_
[0]]) 
 669     for (size_t i(1); i 
!= size_
; ++i
) 
 670         if (!WordEndRange_
[value_
[i
]]) 
 672     const char *value(Value()); 
 673     for (const char **reserved(Reserved_
); *reserved 
!= NULL
; ++reserved
) 
 674         if (strcmp(*reserved
, value
) == 0) 
 679 void CYSwitch::Output(CYOutput 
&out
, CYFlags flags
) const { 
 680     out 
<< "switch" << ' ' << '(' << *value_ 
<< ')' << ' ' << '{'; 
 685 void CYThis::Output(CYOutput 
&out
, CYFlags flags
) const { 
 692 void Throw::Output(CYOutput 
&out
, CYFlags flags
) const { 
 695         out 
<< ' ' << *value_
; 
 699 void Try::Output(CYOutput 
&out
, CYFlags flags
) const { 
 700     out 
<< "try" << ' ' << code_ 
<< catch_ 
<< finally_
; 
 705 void CYVar::Output(CYOutput 
&out
, CYFlags flags
) const { 
 707     declarations_
->Output(out
, flags
); 
 711 void CYVariable::Output(CYOutput 
&out
, CYFlags flags
) const { 
 715 void CYWhile::Output(CYOutput 
&out
, CYFlags flags
) const { 
 716     out 
<< "while" << '(' << *test_ 
<< ')'; 
 717     code_
->Single(out
, CYRight(flags
)); 
 720 void CYWith::Output(CYOutput 
&out
, CYFlags flags
) const { 
 721     out 
<< "with" << '(' << *scope_ 
<< ')'; 
 722     code_
->Single(out
, CYRight(flags
)); 
 725 void CYWord::ClassName(CYOutput 
&out
, bool object
) const { 
 727         out 
<< "objc_getClass("; 
 728     out 
<< '"' << Word() << '"'; 
 733 void CYWord::Output(CYOutput 
&out
) const { 
 735     if (out
.options_
.verbose_
) 
 736         out
.out_ 
<< '@' << this; 
 739 void CYWord::PropertyName(CYOutput 
&out
) const { 
 743 const char *CYWord::Word() const {