]>
git.saurik.com Git - cycript.git/blob - Output.cpp
c06f757d406b767913251ff570bfc93ef63ea630
   1 /* Cycript - Optimizing JavaScript Compiler/Runtime 
   2  * Copyright (C) 2009-2015  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     char last(rhs
[size 
- 1]); 
 103     if (WordEndRange_
[last
] || last 
== '/') 
 109     operator ()(rhs
, size
); 
 113 void CYArgument::Output(CYOutput 
&out
) const { 
 120         value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 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
, CYFlags flags
) const { 
 149 void CYBoolean::Output(CYOutput 
&out
, CYFlags flags
) const { 
 150     out 
<< '!' << (Value() ? "0" : "1"); 
 151     if ((flags 
& CYNoInteger
) != 0) 
 155 void CYBreak::Output(CYOutput 
&out
, CYFlags flags
) const { 
 158         out 
<< ' ' << *label_
; 
 162 void CYCall::Output(CYOutput 
&out
, CYFlags flags
) const { 
 163     bool protect((flags 
& CYNoCall
) != 0); 
 166     function_
->Output(out
, Precedence(), protect 
? CYNoFlags 
: flags
); 
 167     out 
<< '(' << arguments_ 
<< ')'; 
 175 void Catch::Output(CYOutput 
&out
) const { 
 176     out 
<< ' ' << "catch" << ' ' << '(' << *name_ 
<< ')' << ' '; 
 186 void CYComment::Output(CYOutput 
&out
, CYFlags flags
) const { 
 193 void CYCompound::Output(CYOutput 
&out
, CYFlags flags
) const { 
 195         expression_
->Output(out
, flags
); 
 197         expression_
->Output(out
, CYLeft(flags
)); 
 199         next_
->Output(out
, CYRight(flags
)); 
 203 void CYCondition::Output(CYOutput 
&out
, CYFlags flags
) const { 
 204     test_
->Output(out
, Precedence() - 1, CYLeft(flags
)); 
 205     out 
<< ' ' << '?' << ' '; 
 207         true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 208     out 
<< ' ' << ':' << ' '; 
 209     false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
)); 
 212 void CYContinue::Output(CYOutput 
&out
, CYFlags flags
) const { 
 215         out 
<< ' ' << *label_
; 
 219 void CYClause::Output(CYOutput 
&out
) const { 
 222         out 
<< "case" << ' ' << *case_
; 
 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     declarations_
->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 { 
 289     unsigned line(out
.position_
.line
); 
 290     unsigned indent(out
.indent_
); 
 291     code_
->Single(out
, CYCenter(flags
), CYCompactLong
); 
 293     if (out
.position_
.line 
!= line 
&& out
.recent_ 
== indent
) 
 298     out 
<< "while" << ' ' << '(' << *test_ 
<< ')'; 
 301 void CYElement::Output(CYOutput 
&out
) const { 
 303         value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 304     if (next_ 
!= NULL 
|| value_ 
== NULL
) { 
 306         if (next_ 
!= NULL 
&& next_
->value_ 
!= NULL
) 
 313 void CYEmpty::Output(CYOutput 
&out
, CYFlags flags
) const { 
 317 void CYExpress::Output(CYOutput 
&out
, CYFlags flags
) const { 
 318     expression_
->Output(out
, flags 
| CYNoBF
); 
 322 void CYExpression::ClassName(CYOutput 
&out
, bool object
) const { 
 323     Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 326 void CYExpression::ForIn(CYOutput 
&out
, CYFlags flags
) const { 
 327     Output(out
, flags 
| CYNoRightHand
); 
 330 void CYExpression::Output(CYOutput 
&out
) const { 
 331     Output(out
, CYNoFlags
); 
 334 void CYExpression::Output(CYOutput 
&out
, int precedence
, CYFlags flags
) const { 
 335     if (precedence 
< Precedence() || (flags 
& CYNoRightHand
) != 0 && RightHand()) 
 336         out 
<< '(' << *this << ')'; 
 341 void CYExternal::Output(CYOutput 
&out
, CYFlags flags
) const { 
 342     out 
<< "extern" << abi_ 
<< typed_ 
<< ';'; 
 345 void CYFatArrow::Output(CYOutput 
&out
, CYFlags flags
) const { 
 346     out 
<< '(' << parameters_ 
<< ')' << ' ' << "=>" << ' ' << '{' << code_ 
<< '}'; 
 349 void CYFinally::Output(CYOutput 
&out
) const { 
 350     out 
<< ' ' << "finally" << ' '; 
 358 void CYFor::Output(CYOutput 
&out
, CYFlags flags
) const { 
 359     out 
<< "for" << ' ' << '('; 
 360     if (initialiser_ 
!= NULL
) 
 361         initialiser_
->Output(out
, CYNoIn
); 
 367     if (increment_ 
!= NULL
) 
 371     code_
->Single(out
, CYRight(flags
), CYCompactShort
); 
 374 void CYForOf::Output(CYOutput 
&out
, CYFlags flags
) const { 
 375     out 
<< "for" << ' ' << "each" << ' ' << '('; 
 376     initialiser_
->ForIn(out
, CYNoIn
); 
 377     out 
<< ' ' << "in" << ' ' << *set_ 
<< ')'; 
 378     code_
->Single(out
, CYRight(flags
), CYCompactShort
); 
 381 void CYForOfComprehension::Output(CYOutput 
&out
) const { 
 382     out 
<< "for" << ' ' << "each" << ' ' << '(' << *name_ 
<< ' ' << "in" << ' ' << *set_ 
<< ')' << next_
; 
 385 void CYForIn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 386     out 
<< "for" << ' ' << '('; 
 387     if (initialiser_ 
!= NULL
) 
 388         initialiser_
->ForIn(out
, CYNoIn
); 
 389     out 
<< ' ' << "in" << ' ' << *set_ 
<< ')'; 
 390     code_
->Single(out
, CYRight(flags
), CYCompactShort
); 
 393 void CYForInComprehension::Output(CYOutput 
&out
) const { 
 394     out 
<< "for" << ' ' << '(' << *name_ 
<< ' ' << "in" << ' ' << *set_ 
<< ')'; 
 397 void CYFunction::Output(CYOutput 
&out
, CYFlags flags
) const { 
 398     // XXX: one could imagine using + here to save a byte 
 399     bool protect((flags 
& CYNoFunction
) != 0); 
 404         out 
<< ' ' << *name_
; 
 405     out 
<< '(' << parameters_ 
<< ')' << ' '; 
 415 void CYFunctionExpression::Output(CYOutput 
&out
, CYFlags flags
) const { 
 416     CYFunction::Output(out
, flags
); 
 419 void CYFunctionStatement::Output(CYOutput 
&out
, CYFlags flags
) const { 
 420     CYFunction::Output(out
, flags
); 
 423 void CYFunctionParameter::Output(CYOutput 
&out
) const { 
 424     initialiser_
->Output(out
, CYNoFlags
); 
 426         out 
<< ',' << ' ' << *next_
; 
 429 const char *CYIdentifier::Word() const { 
 430     return replace_ 
== NULL 
|| replace_ 
== this ? CYWord::Word() : replace_
->Word(); 
 433 void CYIf::Output(CYOutput 
&out
, CYFlags flags
) const { 
 435     if (false_ 
== NULL 
&& (flags 
& CYNoDangle
) != 0) { 
 440     out 
<< "if" << ' ' << '(' << *test_ 
<< ')'; 
 442     CYFlags 
right(protect 
? CYNoFlags 
: CYRight(flags
)); 
 444     CYFlags 
jacks(CYNoDangle
); 
 448         jacks 
|= protect 
? CYNoFlags 
: CYCenter(flags
); 
 450     unsigned line(out
.position_
.line
); 
 451     unsigned indent(out
.indent_
); 
 452     true_
->Single(out
, jacks
, CYCompactShort
); 
 454     if (false_ 
!= NULL
) { 
 455         if (out
.position_
.line 
!= line 
&& out
.recent_ 
== indent
) 
 461         false_
->Single(out
, right
, CYCompactLong
); 
 468 void CYIfComprehension::Output(CYOutput 
&out
) const { 
 469     out 
<< "if" << ' ' << '(' << *test_ 
<< ')' << next_
; 
 472 void CYImport::Output(CYOutput 
&out
, CYFlags flags
) const { 
 476 void CYIndirectMember::Output(CYOutput 
&out
, CYFlags flags
) const { 
 477     object_
->Output(out
, Precedence(), CYLeft(flags
)); 
 478     if (const char *word 
= property_
->Word()) 
 481         out 
<< "->" << '[' << *property_ 
<< ']'; 
 484 void CYInfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 485     const char *name(Operator()); 
 486     bool protect((flags 
& CYNoIn
) != 0 && strcmp(name
, "in") == 0); 
 489     CYFlags 
left(protect 
? CYNoFlags 
: CYLeft(flags
)); 
 490     lhs_
->Output(out
, Precedence(), left
); 
 491     out 
<< ' ' << name 
<< ' '; 
 492     CYFlags 
right(protect 
? CYNoFlags 
: CYRight(flags
)); 
 493     rhs_
->Output(out
, Precedence() - 1, right
); 
 498 void CYLabel::Output(CYOutput 
&out
, CYFlags flags
) const { 
 499     out 
<< *name_ 
<< ':'; 
 500     statement_
->Single(out
, CYRight(flags
), CYCompactShort
); 
 503 void CYParenthetical::Output(CYOutput 
&out
, CYFlags flags
) const { 
 505     expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
); 
 509 void CYStatement::Output(CYOutput 
&out
) const { 
 513 void CYTypeArrayOf::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 514     next_
->Output(out
, Precedence(), identifier
); 
 520 void CYTypeBlockWith::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 522     next_
->Output(out
, Precedence(), identifier
); 
 523     out 
<< ')' << '(' << parameters_ 
<< ')'; 
 526 void CYTypeConstant::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 527     out 
<< "const" << ' '; 
 528     next_
->Output(out
, Precedence(), identifier
); 
 531 void CYTypeFunctionWith::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 532     next_
->Output(out
, Precedence(), identifier
); 
 533     out 
<< '(' << parameters_ 
<< ')'; 
 536 void CYTypePointerTo::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 538     next_
->Output(out
, Precedence(), identifier
); 
 541 void CYTypeVolatile::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 543     next_
->Output(out
, Precedence(), identifier
); 
 546 void CYTypeModifier::Output(CYOutput 
&out
, int precedence
, CYIdentifier 
*identifier
) const { 
 552     bool protect(precedence 
> Precedence()); 
 556     Output(out
, identifier
); 
 561 void CYTypedIdentifier::Output(CYOutput 
&out
) const { 
 562     specifier_
->Output(out
); 
 563     modifier_
->Output(out
, 0, identifier_
); 
 566 void CYEncodedType::Output(CYOutput 
&out
, CYFlags flags
) const { 
 567     out 
<< "@encode(" << typed_ 
<< ")"; 
 570 void CYTypedParameter::Output(CYOutput 
&out
) const { 
 573         out 
<< ',' << ' ' << next_
; 
 576 void CYLambda::Output(CYOutput 
&out
, CYFlags flags
) const { 
 577     // XXX: this is seriously wrong 
 584 void CYTypeDefinition::Output(CYOutput 
&out
, CYFlags flags
) const { 
 585     out 
<< "typedef" << ' ' << *typed_
; 
 588 void CYLetStatement::Output(CYOutput 
&out
, CYFlags flags
) const { 
 589     out 
<< "let" << ' ' << '(' << *declarations_ 
<< ')'; 
 590     code_
->Single(out
, CYRight(flags
), CYCompactShort
); 
 593 void CYModule::Output(CYOutput 
&out
) const { 
 602 void New::Output(CYOutput 
&out
, CYFlags flags
) const { 
 604     CYFlags 
jacks(CYNoCall 
| CYCenter(flags
)); 
 605     constructor_
->Output(out
, Precedence(), jacks
); 
 606     if (arguments_ 
!= NULL
) 
 607         out 
<< '(' << *arguments_ 
<< ')'; 
 612 void CYNull::Output(CYOutput 
&out
, CYFlags flags
) const { 
 616 void CYNumber::Output(CYOutput 
&out
, CYFlags flags
) const { 
 617     std::ostringstream str
; 
 618     CYNumerify(str
, Value()); 
 619     std::string 
value(str
.str()); 
 620     out 
<< value
.c_str(); 
 621     // XXX: this should probably also handle hex conversions and exponents 
 622     if ((flags 
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
) 
 626 void CYNumber::PropertyName(CYOutput 
&out
) const { 
 627     Output(out
, CYNoFlags
); 
 630 void CYObject::Output(CYOutput 
&out
, CYFlags flags
) const { 
 631     bool protect((flags 
& CYNoBrace
) != 0); 
 643 void CYPostfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 644     lhs_
->Output(out
, Precedence(), CYLeft(flags
)); 
 648 void CYPrefix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 649     const char *name(Operator()); 
 653     rhs_
->Output(out
, Precedence(), CYRight(flags
)); 
 656 void CYProgram::Output(CYOutput 
&out
) const { 
 660 void CYProperty::Output(CYOutput 
&out
) const { 
 662     name_
->PropertyName(out
); 
 664     value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 666         out 
<< ',' << '\n' << *next_
; 
 671 void CYRegEx::Output(CYOutput 
&out
, CYFlags flags
) const { 
 675 void CYReturn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 678         out 
<< ' ' << *value_
; 
 682 void CYRubyBlock::Output(CYOutput 
&out
, CYFlags flags
) const { 
 683     call_
->Output(out
, CYLeft(flags
)); 
 685     proc_
->Output(out
, CYRight(flags
)); 
 688 void CYRubyProc::Output(CYOutput 
&out
, CYFlags flags
) const { 
 689     out 
<< '{' << ' ' << '|' << parameters_ 
<< '|' << '\n'; 
 696 void CYStatement::Multiple(CYOutput 
&out
, CYFlags flags
) const { 
 698     CYForEach (next
, this) { 
 699         bool last(next
->next_ 
== NULL
); 
 700         CYFlags 
jacks(first 
? last 
? flags 
: CYLeft(flags
) : last 
? CYRight(flags
) : CYCenter(flags
)); 
 703         next
->Output(out
, jacks
); 
 708 void CYStatement::Single(CYOutput 
&out
, CYFlags flags
, CYCompactType request
) const { 
 710         return out
.Terminate(); 
 712     _assert(next_ 
== NULL
); 
 714     CYCompactType 
compact(Compact()); 
 716     if (compact 
>= request
) 
 726     if (compact 
< request
) 
 730 void CYString::Output(CYOutput 
&out
, CYFlags flags
) const { 
 731     std::ostringstream str
; 
 732     CYStringify(str
, value_
, size_
); 
 733     out 
<< str
.str().c_str(); 
 736 void CYString::PropertyName(CYOutput 
&out
) const { 
 737     if (const char *word 
= Word()) 
 743 static const char *Reserved_
[] = { 
 744     "false", "null", "true", 
 746     "break", "case", "catch", "continue", "default", 
 747     "delete", "do", "else", "finally", "for", "function", 
 748     "if", "in", "instanceof", "new", "return", "switch", 
 749     "this", "throw", "try", "typeof", "var", "void", 
 754     "class", "enum", "export", "extends", "import", "super", 
 756     "abstract", "boolean", "byte", "char", "double", "final", 
 757     "float", "goto", "int", "long", "native", "short", 
 758     "synchronized", "throws", "transient", "volatile", 
 765 const char *CYString::Word() const { 
 766     if (size_ 
== 0 || !WordStartRange_
[value_
[0]]) 
 768     for (size_t i(1); i 
!= size_
; ++i
) 
 769         if (!WordEndRange_
[value_
[i
]]) 
 771     const char *value(Value()); 
 772     for (const char **reserved(Reserved_
); *reserved 
!= NULL
; ++reserved
) 
 773         if (strcmp(*reserved
, value
) == 0) 
 778 void CYSwitch::Output(CYOutput 
&out
, CYFlags flags
) const { 
 779     out 
<< "switch" << ' ' << '(' << *value_ 
<< ')' << ' ' << '{' << '\n'; 
 786 void CYThis::Output(CYOutput 
&out
, CYFlags flags
) const { 
 793 void Throw::Output(CYOutput 
&out
, CYFlags flags
) const { 
 796         out 
<< ' ' << *value_
; 
 800 void Try::Output(CYOutput 
&out
, CYFlags flags
) const { 
 807     out 
<< catch_ 
<< finally_
; 
 812 void CYTypeError::Output(CYOutput 
&out
) const { 
 816 void CYTypeLong::Output(CYOutput 
&out
) const { 
 817     out 
<< "long" << specifier_
; 
 820 void CYTypeShort::Output(CYOutput 
&out
) const { 
 821     out 
<< "short" << specifier_
; 
 824 void CYTypeSigned::Output(CYOutput 
&out
) const { 
 825     out 
<< "signed" << specifier_
; 
 828 void CYTypeUnsigned::Output(CYOutput 
&out
) const { 
 829     out 
<< "unsigned" << specifier_
; 
 832 void CYTypeVariable::Output(CYOutput 
&out
) const { 
 836 void CYTypeVoid::Output(CYOutput 
&out
) const { 
 840 void CYVar::Output(CYOutput 
&out
, CYFlags flags
) const { 
 842     declarations_
->Output(out
, flags
); 
 846 void CYVariable::Output(CYOutput 
&out
, CYFlags flags
) const { 
 850 void CYWhile::Output(CYOutput 
&out
, CYFlags flags
) const { 
 851     out 
<< "while" << ' ' << '(' << *test_ 
<< ')'; 
 852     code_
->Single(out
, CYRight(flags
), CYCompactShort
); 
 855 void CYWith::Output(CYOutput 
&out
, CYFlags flags
) const { 
 856     out 
<< "with" << ' ' << '(' << *scope_ 
<< ')'; 
 857     code_
->Single(out
, CYRight(flags
), CYCompactShort
); 
 860 void CYWord::ClassName(CYOutput 
&out
, bool object
) const { 
 862         out 
<< "objc_getClass("; 
 863     out 
<< '"' << Word() << '"'; 
 868 void CYWord::Output(CYOutput 
&out
) const { 
 870     if (out
.options_
.verbose_
) { 
 873         sprintf(number
, "%p", this); 
 878 void CYWord::PropertyName(CYOutput 
&out
) const { 
 882 const char *CYWord::Word() const {