]>
git.saurik.com Git - cycript.git/blob - Output.cpp
d6c3a038aeda70a4d6a1c606e889524c84860f6a
   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 CYPostfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 564     lhs_
->Output(out
, Precedence(), CYLeft(flags
)); 
 568 void CYPrefix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 569     const char *name(Operator()); 
 573     rhs_
->Output(out
, Precedence(), CYRight(flags
)); 
 576 void CYProgram::Output(CYOutput 
&out
) const { 
 577     if (statements_ 
!= NULL
) 
 578         statements_
->Multiple(out
); 
 581 void CYProperty::Output(CYOutput 
&out
) const { 
 583     name_
->PropertyName(out
); 
 585     value_
->Output(out
, CYPA
, CYNoFlags
); 
 587         out 
<< ',' << '\n' << *next_
; 
 592 void CYRegEx::Output(CYOutput 
&out
, CYFlags flags
) const { 
 596 void CYReturn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 599         out 
<< ' ' << *value_
; 
 603 void CYStatement::Multiple(CYOutput 
&out
, CYFlags flags
) const { 
 605     for (const CYStatement 
*next(this); next 
!= NULL
; next 
= next
->next_
) { 
 606         bool last(next
->next_ 
== NULL
); 
 607         CYFlags 
jacks(first 
? last 
? flags 
: CYLeft(flags
) : last 
? CYCenter(flags
) : CYRight(flags
)); 
 610         next
->Output(out
, jacks
); 
 615 void CYStatement::Single(CYOutput 
&out
, CYFlags flags
) const { 
 616     _assert(next_ 
== NULL
); 
 625 void CYString::Output(CYOutput 
&out
, CYFlags flags
) const { 
 626     std::ostringstream str
; 
 627     CYStringify(str
, value_
, size_
); 
 628     out 
<< str
.str().c_str(); 
 631 void CYString::PropertyName(CYOutput 
&out
) const { 
 632     if (const char *word 
= Word()) 
 638 static const char *Reserved_
[] = { 
 639     "false", "null", "true", 
 641     "break", "case", "catch", "continue", "default", 
 642     "delete", "do", "else", "finally", "for", "function", 
 643     "if", "in", "instanceof", "new", "return", "switch", 
 644     "this", "throw", "try", "typeof", "var", "void", 
 649     "class", "enum", "export", "extends", "import", "super", 
 651     "abstract", "boolean", "byte", "char", "double", "final", 
 652     "float", "goto", "int", "long", "native", "short", 
 653     "synchronized", "throws", "transient", "volatile", 
 660 const char *CYString::Word() const { 
 661     if (size_ 
== 0 || !WordStartRange_
[value_
[0]]) 
 663     for (size_t i(1); i 
!= size_
; ++i
) 
 664         if (!WordEndRange_
[value_
[i
]]) 
 666     const char *value(Value()); 
 667     for (const char **reserved(Reserved_
); *reserved 
!= NULL
; ++reserved
) 
 668         if (strcmp(*reserved
, value
) == 0) 
 673 void CYSwitch::Output(CYOutput 
&out
, CYFlags flags
) const { 
 674     out 
<< "switch" << ' ' << '(' << *value_ 
<< ')' << ' ' << '{'; 
 679 void CYThis::Output(CYOutput 
&out
, CYFlags flags
) const { 
 686 void Throw::Output(CYOutput 
&out
, CYFlags flags
) const { 
 689         out 
<< ' ' << *value_
; 
 693 void Try::Output(CYOutput 
&out
, CYFlags flags
) const { 
 694     out 
<< "try" << ' ' << code_ 
<< catch_ 
<< finally_
; 
 699 void CYVar::Output(CYOutput 
&out
, CYFlags flags
) const { 
 701     declarations_
->Output(out
, flags
); 
 705 void CYVariable::Output(CYOutput 
&out
, CYFlags flags
) const { 
 709 void CYWhile::Output(CYOutput 
&out
, CYFlags flags
) const { 
 710     out 
<< "while" << '(' << *test_ 
<< ')'; 
 711     code_
->Single(out
, CYRight(flags
)); 
 714 void CYWith::Output(CYOutput 
&out
, CYFlags flags
) const { 
 715     out 
<< "with" << '(' << *scope_ 
<< ')'; 
 716     code_
->Single(out
, CYRight(flags
)); 
 719 void CYWord::ClassName(CYOutput 
&out
, bool object
) const { 
 721         out 
<< "objc_getClass("; 
 722     out 
<< '"' << Word() << '"'; 
 727 void CYWord::Output(CYOutput 
&out
) const { 
 729     if (out
.options_
.verbose_
) 
 730         out
.out_ 
<< '@' << this; 
 733 void CYWord::PropertyName(CYOutput 
&out
) const { 
 737 const char *CYWord::Word() const {