]>
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 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
); 
 121         if (next_
->name_ 
== NULL
) 
 123         out 
<< ' ' << *next_
; 
 127 void CYArray::Output(CYOutput 
&out
, CYFlags flags
) const { 
 128     out 
<< '[' << elements_ 
<< ']'; 
 131 void CYArrayComprehension::Output(CYOutput 
&out
, CYFlags flags
) const { 
 132     out 
<< '[' << *expression_ 
<< ' ' << *comprehensions_ 
<< ']'; 
 135 void CYAssignment::Output(CYOutput 
&out
, CYFlags flags
) const { 
 136     lhs_
->Output(out
, Precedence() - 1, CYLeft(flags
) | CYNoRightHand
); 
 137     out 
<< ' ' << Operator() << ' '; 
 138     rhs_
->Output(out
, Precedence(), CYRight(flags
)); 
 141 void CYBlock::Output(CYOutput 
&out
) const { 
 144     if (statements_ 
!= NULL
) 
 145         statements_
->Multiple(out
); 
 150 void CYBlock::Output(CYOutput 
&out
, CYFlags flags
) const { 
 151     if (statements_ 
== NULL
) 
 153     else if (statements_
->next_ 
== NULL
) 
 154         statements_
->Single(out
, flags
); 
 159 void CYBoolean::Output(CYOutput 
&out
, CYFlags flags
) const { 
 160     out 
<< (Value() ? "true" : "false"); 
 163 void CYBreak::Output(CYOutput 
&out
, CYFlags flags
) const { 
 166         out 
<< ' ' << *label_
; 
 170 void CYCall::Output(CYOutput 
&out
, CYFlags flags
) const { 
 171     bool protect((flags 
& CYNoCall
) != 0); 
 174     function_
->Output(out
, Precedence(), protect 
? CYNoFlags 
: flags
); 
 175     out 
<< '(' << arguments_ 
<< ')'; 
 183 void Catch::Output(CYOutput 
&out
) const { 
 184     out 
<< ' ' << "catch" << ' ' << '(' << *name_ 
<< ')' << ' ' << code_
; 
 189 void CYComment::Output(CYOutput 
&out
, CYFlags flags
) const { 
 196 void CYCompound::Output(CYOutput 
&out
, CYFlags flags
) const { 
 197     if (CYExpression 
*expression 
= expressions_
) 
 198         if (CYExpression 
*next 
= expression
->next_
) { 
 199             expression
->Output(out
, CYLeft(flags
)); 
 200             CYFlags 
center(CYCenter(flags
)); 
 201             while (next 
!= NULL
) { 
 204                 next 
= expression
->next_
; 
 205                 CYFlags 
right(next 
!= NULL 
? center 
: CYRight(flags
)); 
 206                 expression
->Output(out
, right
); 
 209             expression
->Output(out
, flags
); 
 212 void CYCondition::Output(CYOutput 
&out
, CYFlags flags
) const { 
 213     test_
->Output(out
, Precedence() - 1, CYLeft(flags
)); 
 214     out 
<< ' ' << '?' << ' '; 
 216         true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 217     out 
<< ' ' << ':' << ' '; 
 218     false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
)); 
 221 void CYContinue::Output(CYOutput 
&out
, CYFlags flags
) const { 
 224         out 
<< ' ' << *label_
; 
 228 void CYClause::Output(CYOutput 
&out
) const { 
 230         out 
<< "case" << ' ' << *case_
; 
 234     if (statements_ 
!= NULL
) 
 235         statements_
->Multiple(out
); 
 239 void CYDeclaration::ForIn(CYOutput 
&out
, CYFlags flags
) const { 
 241     Output(out
, CYRight(flags
)); 
 244 void CYDeclaration::Output(CYOutput 
&out
, CYFlags flags
) const { 
 246     //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_; 
 247     if (initialiser_ 
!= NULL
) { 
 248         out 
<< ' ' << '=' << ' '; 
 249         initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
)); 
 253 void CYDeclarations::For(CYOutput 
&out
) const { 
 258 void CYDeclarations::Output(CYOutput 
&out
) const { 
 259     Output(out
, CYNoFlags
); 
 262 void CYDeclarations::Output(CYOutput 
&out
, CYFlags flags
) const { 
 263     const CYDeclarations 
*declaration(this); 
 266     CYDeclarations 
*next(declaration
->next_
); 
 267     CYFlags 
jacks(first 
? CYLeft(flags
) : next 
== NULL 
? CYRight(flags
) : CYCenter(flags
)); 
 269     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::For(CYOutput 
&out
) const { 
 321 void CYExpression::ForIn(CYOutput 
&out
, CYFlags flags
) const { 
 322     Output(out
, flags 
| CYNoRightHand
); 
 325 void CYExpression::Output(CYOutput 
&out
) const { 
 326     Output(out
, CYNoFlags
); 
 329 void CYExpression::Output(CYOutput 
&out
, unsigned precedence
, CYFlags flags
) const { 
 330     if (precedence 
< Precedence() || (flags 
& CYNoRightHand
) != 0 && RightHand()) 
 331         out 
<< '(' << *this << ')'; 
 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_
->For(out
); 
 349     if (increment_ 
!= NULL
) 
 353     code_
->Single(out
, CYRight(flags
)); 
 356 void CYForEachIn::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 CYForEachInComprehension::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 { 
 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 CYLet::Output(CYOutput 
&out
, CYFlags flags
) const { 
 471     out 
<< "let" << ' ' << '(' << *declarations_ 
<< ')' << ' ' << code_
; 
 477 void New::Output(CYOutput 
&out
, CYFlags flags
) const { 
 479     CYFlags 
jacks(CYNoCall 
| CYCenter(flags
)); 
 480     constructor_
->Output(out
, Precedence(), jacks
); 
 481     if (arguments_ 
!= NULL
) 
 482         out 
<< '(' << *arguments_ 
<< ')'; 
 487 void CYNull::Output(CYOutput 
&out
, CYFlags flags
) const { 
 491 void CYNumber::Output(CYOutput 
&out
, CYFlags flags
) const { 
 492     std::ostringstream str
; 
 493     CYNumerify(str
, Value()); 
 494     std::string 
value(str
.str()); 
 495     out 
<< value
.c_str(); 
 496     // XXX: this should probably also handle hex conversions and exponents 
 497     if ((flags 
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
) 
 501 void CYNumber::PropertyName(CYOutput 
&out
) const { 
 502     Output(out
, CYNoFlags
); 
 505 void CYObject::Output(CYOutput 
&out
, CYFlags flags
) const { 
 506     bool protect((flags 
& CYNoBrace
) != 0); 
 518 void CYOptionalFunctionParameter::Output(CYOutput 
&out
) const { 
 519     out 
<< *name_ 
<< '='; 
 520     initializer_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 522         out 
<< ',' << ' ' << *next_
; 
 525 void CYPostfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 526     lhs_
->Output(out
, Precedence(), CYLeft(flags
)); 
 530 void CYPrefix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 531     const char *name(Operator()); 
 535     rhs_
->Output(out
, Precedence(), CYRight(flags
)); 
 538 void CYProgram::Output(CYOutput 
&out
) const { 
 539     if (statements_ 
!= NULL
) 
 540         statements_
->Multiple(out
); 
 543 void CYProperty::Output(CYOutput 
&out
) const { 
 545     name_
->PropertyName(out
); 
 547     value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 549         out 
<< ',' << '\n' << *next_
; 
 554 void CYRegEx::Output(CYOutput 
&out
, CYFlags flags
) const { 
 558 void CYReturn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 561         out 
<< ' ' << *value_
; 
 565 void CYRubyBlock::Output(CYOutput 
&out
, CYFlags flags
) const { 
 566     call_
->Output(out
, CYLeft(flags
)); 
 568     proc_
->Output(out
, CYRight(flags
)); 
 571 void CYRubyProc::Output(CYOutput 
&out
, CYFlags flags
) const { 
 572     // XXX: this is not outputting the parameters 
 576 void CYStatement::Multiple(CYOutput 
&out
, CYFlags flags
) const { 
 578     CYForEach (next
, this) { 
 579         bool last(next
->next_ 
== NULL
); 
 580         CYFlags 
jacks(first 
? last 
? flags 
: CYLeft(flags
) : last 
? CYRight(flags
) : CYCenter(flags
)); 
 583         next
->Output(out
, jacks
); 
 588 void CYStatement::Single(CYOutput 
&out
, CYFlags flags
) const { 
 589     _assert(next_ 
== NULL
); 
 598 void CYString::Output(CYOutput 
&out
, CYFlags flags
) const { 
 599     std::ostringstream str
; 
 600     CYStringify(str
, value_
, size_
); 
 601     out 
<< str
.str().c_str(); 
 604 void CYString::PropertyName(CYOutput 
&out
) const { 
 605     if (const char *word 
= Word()) 
 611 static const char *Reserved_
[] = { 
 612     "false", "null", "true", 
 614     "break", "case", "catch", "continue", "default", 
 615     "delete", "do", "else", "finally", "for", "function", 
 616     "if", "in", "instanceof", "new", "return", "switch", 
 617     "this", "throw", "try", "typeof", "var", "void", 
 622     "class", "enum", "export", "extends", "import", "super", 
 624     "abstract", "boolean", "byte", "char", "double", "final", 
 625     "float", "goto", "int", "long", "native", "short", 
 626     "synchronized", "throws", "transient", "volatile", 
 633 const char *CYString::Word() const { 
 634     if (size_ 
== 0 || !WordStartRange_
[value_
[0]]) 
 636     for (size_t i(1); i 
!= size_
; ++i
) 
 637         if (!WordEndRange_
[value_
[i
]]) 
 639     const char *value(Value()); 
 640     for (const char **reserved(Reserved_
); *reserved 
!= NULL
; ++reserved
) 
 641         if (strcmp(*reserved
, value
) == 0) 
 646 void CYSwitch::Output(CYOutput 
&out
, CYFlags flags
) const { 
 647     out 
<< "switch" << ' ' << '(' << *value_ 
<< ')' << ' ' << '{'; 
 652 void CYThis::Output(CYOutput 
&out
, CYFlags flags
) const { 
 659 void Throw::Output(CYOutput 
&out
, CYFlags flags
) const { 
 662         out 
<< ' ' << *value_
; 
 666 void Try::Output(CYOutput 
&out
, CYFlags flags
) const { 
 667     out 
<< "try" << ' ' << code_ 
<< catch_ 
<< finally_
; 
 672 void CYVar::Output(CYOutput 
&out
, CYFlags flags
) const { 
 674     declarations_
->Output(out
, flags
); 
 678 void CYVariable::Output(CYOutput 
&out
, CYFlags flags
) const { 
 682 void CYWhile::Output(CYOutput 
&out
, CYFlags flags
) const { 
 683     out 
<< "while" << '(' << *test_ 
<< ')'; 
 684     code_
->Single(out
, CYRight(flags
)); 
 687 void CYWith::Output(CYOutput 
&out
, CYFlags flags
) const { 
 688     out 
<< "with" << '(' << *scope_ 
<< ')'; 
 689     code_
->Single(out
, CYRight(flags
)); 
 692 void CYWord::ClassName(CYOutput 
&out
, bool object
) const { 
 694         out 
<< "objc_getClass("; 
 695     out 
<< '"' << Word() << '"'; 
 700 void CYWord::Output(CYOutput 
&out
) const { 
 702     if (out
.options_
.verbose_
) 
 703         out
.out_ 
<< '@' << this; 
 706 void CYWord::PropertyName(CYOutput 
&out
) const { 
 710 const char *CYWord::Word() const {