]>
git.saurik.com Git - cycript.git/blob - Output.cpp
467825cfdfeeaf5230cca96495752b45d3aea769
   1 /* Cycript - Optimizing JavaScript Compiler/Runtime 
   2  * Copyright (C) 2009-2014  Jay Freeman (saurik) 
   5 /* GNU Affero General Public License, Version 3 {{{ */ 
   7  * This program is free software: you can redistribute it and/or modify 
   8  * it under the terms of the GNU Affero General Public License as published by 
   9  * the Free Software Foundation, either version 3 of the License, or 
  10  * (at your option) any later version. 
  12  * This program is distributed in the hope that it will be useful, 
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  * GNU Affero General Public License for more details. 
  17  * You should have received a copy of the GNU Affero General Public License 
  18  * along with this program.  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 CYExternal::Output(CYOutput 
&out
, CYFlags flags
) const { 
 333     out 
<< "extern" << abi_ 
<< typed_ 
<< ';'; 
 336 void CYFatArrow::Output(CYOutput 
&out
, CYFlags flags
) const { 
 337     out 
<< '(' << parameters_ 
<< ')' << ' ' << "=>" << ' ' << code_
; 
 340 void CYFinally::Output(CYOutput 
&out
) const { 
 341     out 
<< ' ' << "finally" << ' ' << code_
; 
 344 void CYFor::Output(CYOutput 
&out
, CYFlags flags
) const { 
 345     out 
<< "for" << ' ' << '('; 
 346     if (initialiser_ 
!= NULL
) 
 347         initialiser_
->Output(out
, CYNoIn
); 
 353     if (increment_ 
!= NULL
) 
 357     code_
->Single(out
, CYRight(flags
)); 
 360 void CYForOf::Output(CYOutput 
&out
, CYFlags flags
) const { 
 361     out 
<< "for" << ' ' << "each" << ' ' << '('; 
 362     initialiser_
->ForIn(out
, CYNoIn
); 
 363     out 
<< "in" << *set_ 
<< ')'; 
 364     code_
->Single(out
, CYRight(flags
)); 
 367 void CYForOfComprehension::Output(CYOutput 
&out
) const { 
 368     out 
<< "for" << ' ' << "each" << ' ' << '(' << *name_ 
<< ' ' << "in" << ' ' << *set_ 
<< ')' << next_
; 
 371 void CYForIn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 372     out 
<< "for" << ' ' << '('; 
 373     if (initialiser_ 
!= NULL
) 
 374         initialiser_
->ForIn(out
, CYNoIn
); 
 375     out 
<< "in" << *set_ 
<< ')'; 
 376     code_
->Single(out
, CYRight(flags
)); 
 379 void CYForInComprehension::Output(CYOutput 
&out
) const { 
 380     out 
<< "for" << ' ' << '(' << *name_ 
<< ' ' << "in" << ' ' << *set_ 
<< ')'; 
 383 void CYFunction::Output(CYOutput 
&out
, CYFlags flags
) const { 
 384     // XXX: one could imagine using + here to save a byte 
 385     bool protect((flags 
& CYNoFunction
) != 0); 
 390         out 
<< ' ' << *name_
; 
 391     out 
<< '(' << parameters_ 
<< ')'; 
 397 void CYFunctionExpression::Output(CYOutput 
&out
, CYFlags flags
) const { 
 398     CYFunction::Output(out
, flags
); 
 401 void CYFunctionStatement::Output(CYOutput 
&out
, CYFlags flags
) const { 
 402     CYFunction::Output(out
, flags
); 
 405 void CYFunctionParameter::Output(CYOutput 
&out
) const { 
 406     initialiser_
->Output(out
, CYNoFlags
); 
 408         out 
<< ',' << ' ' << *next_
; 
 411 const char *CYIdentifier::Word() const { 
 412     return replace_ 
== NULL 
|| replace_ 
== this ? CYWord::Word() : replace_
->Word(); 
 415 void CYIf::Output(CYOutput 
&out
, CYFlags flags
) const { 
 417     if (false_ 
== NULL 
&& (flags 
& CYNoDangle
) != 0) { 
 422     out 
<< "if" << ' ' << '(' << *test_ 
<< ')'; 
 424     CYFlags 
right(protect 
? CYNoFlags 
: CYRight(flags
)); 
 426     CYFlags 
jacks(CYNoDangle
); 
 430         jacks 
|= protect 
? CYNoFlags 
: CYCenter(flags
); 
 432     true_
->Single(out
, jacks
); 
 434     if (false_ 
!= NULL
) { 
 435         out 
<< '\t' << "else"; 
 436         false_
->Single(out
, right
); 
 443 void CYIfComprehension::Output(CYOutput 
&out
) const { 
 444     out 
<< "if" << ' ' << '(' << *test_ 
<< ')' << next_
; 
 447 void CYImport::Output(CYOutput 
&out
, CYFlags flags
) const { 
 451 void CYIndirectMember::Output(CYOutput 
&out
, CYFlags flags
) const { 
 452     object_
->Output(out
, Precedence(), CYLeft(flags
)); 
 453     if (const char *word 
= property_
->Word()) 
 456         out 
<< "->" << '[' << *property_ 
<< ']'; 
 459 void CYInfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 460     const char *name(Operator()); 
 461     bool protect((flags 
& CYNoIn
) != 0 && strcmp(name
, "in") == 0); 
 464     CYFlags 
left(protect 
? CYNoFlags 
: CYLeft(flags
)); 
 465     lhs_
->Output(out
, Precedence(), left
); 
 466     out 
<< ' ' << name 
<< ' '; 
 467     CYFlags 
right(protect 
? CYNoFlags 
: CYRight(flags
)); 
 468     rhs_
->Output(out
, Precedence() - 1, right
); 
 473 void CYLabel::Output(CYOutput 
&out
, CYFlags flags
) const { 
 474     out 
<< *name_ 
<< ':' << ' '; 
 475     statement_
->Single(out
, CYRight(flags
)); 
 478 void CYTypeArrayOf::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 479     next_
->Output(out
, Precedence(), identifier
); 
 485 void CYTypeBlockWith::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 487     next_
->Output(out
, Precedence(), identifier
); 
 488     out 
<< ')' << '(' << parameters_ 
<< ')'; 
 491 void CYTypeConstant::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 493     next_
->Output(out
, Precedence(), identifier
); 
 496 void CYTypeFunctionWith::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 497     next_
->Output(out
, Precedence(), identifier
); 
 498     out 
<< '(' << parameters_ 
<< ')'; 
 501 void CYTypePointerTo::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 503     next_
->Output(out
, Precedence(), identifier
); 
 506 void CYTypeVolatile::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 508     next_
->Output(out
, Precedence(), identifier
); 
 511 void CYTypeModifier::Output(CYOutput 
&out
, int precedence
, CYIdentifier 
*identifier
) const { 
 517     bool protect(precedence 
> Precedence()); 
 521     Output(out
, identifier
); 
 526 void CYTypedIdentifier::Output(CYOutput 
&out
) const { 
 527     specifier_
->Output(out
); 
 528     modifier_
->Output(out
, 0, identifier_
); 
 531 void CYEncodedType::Output(CYOutput 
&out
, CYFlags flags
) const { 
 532     out 
<< "@encode(" << typed_ 
<< ")"; 
 535 void CYTypedParameter::Output(CYOutput 
&out
) const { 
 538         out 
<< ',' << ' ' << next_
; 
 541 void CYLambda::Output(CYOutput 
&out
, CYFlags flags
) const { 
 542     // XXX: this is seriously wrong 
 549 void CYTypeDefinition::Output(CYOutput 
&out
, CYFlags flags
) const { 
 550     out 
<< "typedef" << *typed_
; 
 553 void CYLetStatement::Output(CYOutput 
&out
, CYFlags flags
) const { 
 554     out 
<< "let" << ' ' << '(' << *declarations_ 
<< ')'; 
 555     code_
->Single(out
, CYRight(flags
)); 
 558 void CYModule::Output(CYOutput 
&out
) const { 
 567 void New::Output(CYOutput 
&out
, CYFlags flags
) const { 
 569     CYFlags 
jacks(CYNoCall 
| CYCenter(flags
)); 
 570     constructor_
->Output(out
, Precedence(), jacks
); 
 571     if (arguments_ 
!= NULL
) 
 572         out 
<< '(' << *arguments_ 
<< ')'; 
 577 void CYNull::Output(CYOutput 
&out
, CYFlags flags
) const { 
 581 void CYNumber::Output(CYOutput 
&out
, CYFlags flags
) const { 
 582     std::ostringstream str
; 
 583     CYNumerify(str
, Value()); 
 584     std::string 
value(str
.str()); 
 585     out 
<< value
.c_str(); 
 586     // XXX: this should probably also handle hex conversions and exponents 
 587     if ((flags 
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
) 
 591 void CYNumber::PropertyName(CYOutput 
&out
) const { 
 592     Output(out
, CYNoFlags
); 
 595 void CYObject::Output(CYOutput 
&out
, CYFlags flags
) const { 
 596     bool protect((flags 
& CYNoBrace
) != 0); 
 608 void CYPostfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 609     lhs_
->Output(out
, Precedence(), CYLeft(flags
)); 
 613 void CYPrefix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 614     const char *name(Operator()); 
 618     rhs_
->Output(out
, Precedence(), CYRight(flags
)); 
 621 void CYProgram::Output(CYOutput 
&out
) const { 
 622     if (statements_ 
!= NULL
) 
 623         statements_
->Multiple(out
); 
 626 void CYProperty::Output(CYOutput 
&out
) const { 
 628     name_
->PropertyName(out
); 
 630     value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 632         out 
<< ',' << '\n' << *next_
; 
 637 void CYRegEx::Output(CYOutput 
&out
, CYFlags flags
) const { 
 641 void CYReturn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 644         out 
<< ' ' << *value_
; 
 648 void CYRubyBlock::Output(CYOutput 
&out
, CYFlags flags
) const { 
 649     call_
->Output(out
, CYLeft(flags
)); 
 651     proc_
->Output(out
, CYRight(flags
)); 
 654 void CYRubyProc::Output(CYOutput 
&out
, CYFlags flags
) const { 
 655     // XXX: this is not outputting the parameters 
 659 void CYStatement::Multiple(CYOutput 
&out
, CYFlags flags
) const { 
 661     CYForEach (next
, this) { 
 662         bool last(next
->next_ 
== NULL
); 
 663         CYFlags 
jacks(first 
? last 
? flags 
: CYLeft(flags
) : last 
? CYRight(flags
) : CYCenter(flags
)); 
 666         next
->Output(out
, jacks
); 
 671 void CYStatement::Single(CYOutput 
&out
, CYFlags flags
) const { 
 673         return out
.Terminate(); 
 675     _assert(next_ 
== NULL
); 
 684 void CYString::Output(CYOutput 
&out
, CYFlags flags
) const { 
 685     std::ostringstream str
; 
 686     CYStringify(str
, value_
, size_
); 
 687     out 
<< str
.str().c_str(); 
 690 void CYString::PropertyName(CYOutput 
&out
) const { 
 691     if (const char *word 
= Word()) 
 697 static const char *Reserved_
[] = { 
 698     "false", "null", "true", 
 700     "break", "case", "catch", "continue", "default", 
 701     "delete", "do", "else", "finally", "for", "function", 
 702     "if", "in", "instanceof", "new", "return", "switch", 
 703     "this", "throw", "try", "typeof", "var", "void", 
 708     "class", "enum", "export", "extends", "import", "super", 
 710     "abstract", "boolean", "byte", "char", "double", "final", 
 711     "float", "goto", "int", "long", "native", "short", 
 712     "synchronized", "throws", "transient", "volatile", 
 719 const char *CYString::Word() const { 
 720     if (size_ 
== 0 || !WordStartRange_
[value_
[0]]) 
 722     for (size_t i(1); i 
!= size_
; ++i
) 
 723         if (!WordEndRange_
[value_
[i
]]) 
 725     const char *value(Value()); 
 726     for (const char **reserved(Reserved_
); *reserved 
!= NULL
; ++reserved
) 
 727         if (strcmp(*reserved
, value
) == 0) 
 732 void CYSwitch::Output(CYOutput 
&out
, CYFlags flags
) const { 
 733     out 
<< "switch" << ' ' << '(' << *value_ 
<< ')' << ' ' << '{'; 
 738 void CYThis::Output(CYOutput 
&out
, CYFlags flags
) const { 
 745 void Throw::Output(CYOutput 
&out
, CYFlags flags
) const { 
 748         out 
<< ' ' << *value_
; 
 752 void Try::Output(CYOutput 
&out
, CYFlags flags
) const { 
 753     out 
<< "try" << ' ' << code_ 
<< catch_ 
<< finally_
; 
 758 void CYTypeError::Output(CYOutput 
&out
) const { 
 762 void CYTypeLong::Output(CYOutput 
&out
) const { 
 763     out 
<< "long" << specifier_
; 
 766 void CYTypeShort::Output(CYOutput 
&out
) const { 
 767     out 
<< "short" << specifier_
; 
 770 void CYTypeSigned::Output(CYOutput 
&out
) const { 
 771     out 
<< "signed" << specifier_
; 
 774 void CYTypeUnsigned::Output(CYOutput 
&out
) const { 
 775     out 
<< "unsigned" << specifier_
; 
 778 void CYTypeVariable::Output(CYOutput 
&out
) const { 
 782 void CYTypeVoid::Output(CYOutput 
&out
) const { 
 786 void CYVar::Output(CYOutput 
&out
, CYFlags flags
) const { 
 788     declarations_
->Output(out
, flags
); 
 792 void CYVariable::Output(CYOutput 
&out
, CYFlags flags
) const { 
 796 void CYWhile::Output(CYOutput 
&out
, CYFlags flags
) const { 
 797     out 
<< "while" << '(' << *test_ 
<< ')'; 
 798     code_
->Single(out
, CYRight(flags
)); 
 801 void CYWith::Output(CYOutput 
&out
, CYFlags flags
) const { 
 802     out 
<< "with" << '(' << *scope_ 
<< ')'; 
 803     code_
->Single(out
, CYRight(flags
)); 
 806 void CYWord::ClassName(CYOutput 
&out
, bool object
) const { 
 808         out 
<< "objc_getClass("; 
 809     out 
<< '"' << Word() << '"'; 
 814 void CYWord::Output(CYOutput 
&out
) const { 
 816     if (out
.options_
.verbose_
) 
 817         out
.out_ 
<< '@' << this; 
 820 void CYWord::PropertyName(CYOutput 
&out
) const { 
 824 const char *CYWord::Word() const {