]>
git.saurik.com Git - cycript.git/blob - Output.cpp
cdfe1bd1e4a3c5c8a49c8f3deeb47678dd2549c2
   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 
== '/') 
 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() ? "true" : "false"); 
 153 void CYBreak::Output(CYOutput 
&out
, CYFlags flags
) const { 
 156         out 
<< ' ' << *label_
; 
 160 void CYCall::Output(CYOutput 
&out
, CYFlags flags
) const { 
 161     bool protect((flags 
& CYNoCall
) != 0); 
 164     function_
->Output(out
, Precedence(), protect 
? CYNoFlags 
: flags
); 
 165     out 
<< '(' << arguments_ 
<< ')'; 
 173 void Catch::Output(CYOutput 
&out
) const { 
 174     out 
<< ' ' << "catch" << ' ' << '(' << *name_ 
<< ')' << ' '; 
 184 void CYComment::Output(CYOutput 
&out
, CYFlags flags
) const { 
 191 void CYCompound::Output(CYOutput 
&out
, CYFlags flags
) const { 
 193         expression_
->Output(out
, flags
); 
 195         expression_
->Output(out
, CYLeft(flags
)); 
 197         next_
->Output(out
, CYRight(flags
)); 
 201 void CYCondition::Output(CYOutput 
&out
, CYFlags flags
) const { 
 202     test_
->Output(out
, Precedence() - 1, CYLeft(flags
)); 
 203     out 
<< ' ' << '?' << ' '; 
 205         true_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 206     out 
<< ' ' << ':' << ' '; 
 207     false_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
)); 
 210 void CYContinue::Output(CYOutput 
&out
, CYFlags flags
) const { 
 213         out 
<< ' ' << *label_
; 
 217 void CYClause::Output(CYOutput 
&out
) const { 
 219         out 
<< "case" << ' ' << *case_
; 
 227 void CYDebugger::Output(CYOutput 
&out
, CYFlags flags
) const { 
 228     out 
<< "debugger" << ';'; 
 231 void CYDeclaration::ForIn(CYOutput 
&out
, CYFlags flags
) const { 
 233     Output(out
, CYRight(flags
)); 
 236 void CYDeclaration::Output(CYOutput 
&out
, CYFlags flags
) const { 
 238     //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_; 
 239     if (initialiser_ 
!= NULL
) { 
 240         out 
<< ' ' << '=' << ' '; 
 241         initialiser_
->Output(out
, CYAssign::Precedence_
, CYRight(flags
)); 
 245 void CYForDeclarations::Output(CYOutput 
&out
, CYFlags flags
) const { 
 247     declarations_
->Output(out
, CYRight(flags
)); 
 250 void CYDeclarations::Output(CYOutput 
&out
) const { 
 251     Output(out
, CYNoFlags
); 
 254 void CYDeclarations::Output(CYOutput 
&out
, CYFlags flags
) const { 
 255     const CYDeclarations 
*declaration(this); 
 259         CYDeclarations 
*next(declaration
->next_
); 
 261         CYFlags 
jacks(first 
? CYLeft(flags
) : next 
== NULL 
? CYRight(flags
) : CYCenter(flags
)); 
 263         declaration
->declaration_
->Output(out
, jacks
); 
 273 void CYDirectMember::Output(CYOutput 
&out
, CYFlags flags
) const { 
 274     object_
->Output(out
, Precedence(), CYLeft(flags
) | CYNoInteger
); 
 275     if (const char *word 
= property_
->Word()) 
 278         out 
<< '[' << *property_ 
<< ']'; 
 281 void CYDoWhile::Output(CYOutput 
&out
, CYFlags flags
) const { 
 283     code_
->Single(out
, CYCenter(flags
)); 
 284     out 
<< "while" << ' ' << '(' << *test_ 
<< ')'; 
 287 void CYElement::Output(CYOutput 
&out
) const { 
 289         value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 290     if (next_ 
!= NULL 
|| value_ 
== NULL
) { 
 292         if (next_ 
!= NULL 
&& next_
->value_ 
!= NULL
) 
 299 void CYEmpty::Output(CYOutput 
&out
, CYFlags flags
) const { 
 303 void CYExpress::Output(CYOutput 
&out
, CYFlags flags
) const { 
 304     expression_
->Output(out
, flags 
| CYNoBF
); 
 308 void CYExpression::ClassName(CYOutput 
&out
, bool object
) const { 
 309     Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 312 void CYExpression::ForIn(CYOutput 
&out
, CYFlags flags
) const { 
 313     Output(out
, flags 
| CYNoRightHand
); 
 316 void CYExpression::Output(CYOutput 
&out
) const { 
 317     Output(out
, CYNoFlags
); 
 320 void CYExpression::Output(CYOutput 
&out
, int precedence
, CYFlags flags
) const { 
 321     if (precedence 
< Precedence() || (flags 
& CYNoRightHand
) != 0 && RightHand()) 
 322         out 
<< '(' << *this << ')'; 
 327 void CYExternal::Output(CYOutput 
&out
, CYFlags flags
) const { 
 328     out 
<< "extern" << abi_ 
<< typed_ 
<< ';'; 
 331 void CYFatArrow::Output(CYOutput 
&out
, CYFlags flags
) const { 
 332     out 
<< '(' << parameters_ 
<< ')' << ' ' << "=>" << ' ' << '{' << code_ 
<< '}'; 
 335 void CYFinally::Output(CYOutput 
&out
) const { 
 336     out 
<< ' ' << "finally" << ' '; 
 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_ 
<< ')' << ' '; 
 401 void CYFunctionExpression::Output(CYOutput 
&out
, CYFlags flags
) const { 
 402     CYFunction::Output(out
, flags
); 
 405 void CYFunctionStatement::Output(CYOutput 
&out
, CYFlags flags
) const { 
 406     CYFunction::Output(out
, flags
); 
 409 void CYFunctionParameter::Output(CYOutput 
&out
) const { 
 410     initialiser_
->Output(out
, CYNoFlags
); 
 412         out 
<< ',' << ' ' << *next_
; 
 415 const char *CYIdentifier::Word() const { 
 416     return replace_ 
== NULL 
|| replace_ 
== this ? CYWord::Word() : replace_
->Word(); 
 419 void CYIf::Output(CYOutput 
&out
, CYFlags flags
) const { 
 421     if (false_ 
== NULL 
&& (flags 
& CYNoDangle
) != 0) { 
 426     out 
<< "if" << ' ' << '(' << *test_ 
<< ')'; 
 428     CYFlags 
right(protect 
? CYNoFlags 
: CYRight(flags
)); 
 430     CYFlags 
jacks(CYNoDangle
); 
 434         jacks 
|= protect 
? CYNoFlags 
: CYCenter(flags
); 
 436     true_
->Single(out
, jacks
); 
 438     if (false_ 
!= NULL
) { 
 439         out 
<< '\t' << "else"; 
 440         false_
->Single(out
, right
); 
 447 void CYIfComprehension::Output(CYOutput 
&out
) const { 
 448     out 
<< "if" << ' ' << '(' << *test_ 
<< ')' << next_
; 
 451 void CYImport::Output(CYOutput 
&out
, CYFlags flags
) const { 
 455 void CYIndirectMember::Output(CYOutput 
&out
, CYFlags flags
) const { 
 456     object_
->Output(out
, Precedence(), CYLeft(flags
)); 
 457     if (const char *word 
= property_
->Word()) 
 460         out 
<< "->" << '[' << *property_ 
<< ']'; 
 463 void CYInfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 464     const char *name(Operator()); 
 465     bool protect((flags 
& CYNoIn
) != 0 && strcmp(name
, "in") == 0); 
 468     CYFlags 
left(protect 
? CYNoFlags 
: CYLeft(flags
)); 
 469     lhs_
->Output(out
, Precedence(), left
); 
 470     out 
<< ' ' << name 
<< ' '; 
 471     CYFlags 
right(protect 
? CYNoFlags 
: CYRight(flags
)); 
 472     rhs_
->Output(out
, Precedence() - 1, right
); 
 477 void CYLabel::Output(CYOutput 
&out
, CYFlags flags
) const { 
 478     out 
<< *name_ 
<< ':' << ' '; 
 479     statement_
->Single(out
, CYRight(flags
)); 
 482 void CYParenthetical::Output(CYOutput 
&out
, CYFlags flags
) const { 
 484     expression_
->Output(out
, CYCompound::Precedence_
, CYNoFlags
); 
 488 void CYStatement::Output(CYOutput 
&out
) const { 
 492 void CYTypeArrayOf::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 493     next_
->Output(out
, Precedence(), identifier
); 
 499 void CYTypeBlockWith::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 501     next_
->Output(out
, Precedence(), identifier
); 
 502     out 
<< ')' << '(' << parameters_ 
<< ')'; 
 505 void CYTypeConstant::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 507     next_
->Output(out
, Precedence(), identifier
); 
 510 void CYTypeFunctionWith::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 511     next_
->Output(out
, Precedence(), identifier
); 
 512     out 
<< '(' << parameters_ 
<< ')'; 
 515 void CYTypePointerTo::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 517     next_
->Output(out
, Precedence(), identifier
); 
 520 void CYTypeVolatile::Output(CYOutput 
&out
, CYIdentifier 
*identifier
) const { 
 522     next_
->Output(out
, Precedence(), identifier
); 
 525 void CYTypeModifier::Output(CYOutput 
&out
, int precedence
, CYIdentifier 
*identifier
) const { 
 531     bool protect(precedence 
> Precedence()); 
 535     Output(out
, identifier
); 
 540 void CYTypedIdentifier::Output(CYOutput 
&out
) const { 
 541     specifier_
->Output(out
); 
 542     modifier_
->Output(out
, 0, identifier_
); 
 545 void CYEncodedType::Output(CYOutput 
&out
, CYFlags flags
) const { 
 546     out 
<< "@encode(" << typed_ 
<< ")"; 
 549 void CYTypedParameter::Output(CYOutput 
&out
) const { 
 552         out 
<< ',' << ' ' << next_
; 
 555 void CYLambda::Output(CYOutput 
&out
, CYFlags flags
) const { 
 556     // XXX: this is seriously wrong 
 563 void CYTypeDefinition::Output(CYOutput 
&out
, CYFlags flags
) const { 
 564     out 
<< "typedef" << *typed_
; 
 567 void CYLetStatement::Output(CYOutput 
&out
, CYFlags flags
) const { 
 568     out 
<< "let" << ' ' << '(' << *declarations_ 
<< ')'; 
 569     code_
->Single(out
, CYRight(flags
)); 
 572 void CYModule::Output(CYOutput 
&out
) const { 
 581 void New::Output(CYOutput 
&out
, CYFlags flags
) const { 
 583     CYFlags 
jacks(CYNoCall 
| CYCenter(flags
)); 
 584     constructor_
->Output(out
, Precedence(), jacks
); 
 585     if (arguments_ 
!= NULL
) 
 586         out 
<< '(' << *arguments_ 
<< ')'; 
 591 void CYNull::Output(CYOutput 
&out
, CYFlags flags
) const { 
 595 void CYNumber::Output(CYOutput 
&out
, CYFlags flags
) const { 
 596     std::ostringstream str
; 
 597     CYNumerify(str
, Value()); 
 598     std::string 
value(str
.str()); 
 599     out 
<< value
.c_str(); 
 600     // XXX: this should probably also handle hex conversions and exponents 
 601     if ((flags 
& CYNoInteger
) != 0 && value
.find('.') == std::string::npos
) 
 605 void CYNumber::PropertyName(CYOutput 
&out
) const { 
 606     Output(out
, CYNoFlags
); 
 609 void CYObject::Output(CYOutput 
&out
, CYFlags flags
) const { 
 610     bool protect((flags 
& CYNoBrace
) != 0); 
 622 void CYPostfix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 623     lhs_
->Output(out
, Precedence(), CYLeft(flags
)); 
 627 void CYPrefix::Output(CYOutput 
&out
, CYFlags flags
) const { 
 628     const char *name(Operator()); 
 632     rhs_
->Output(out
, Precedence(), CYRight(flags
)); 
 635 void CYProgram::Output(CYOutput 
&out
) const { 
 639 void CYProperty::Output(CYOutput 
&out
) const { 
 641     name_
->PropertyName(out
); 
 643     value_
->Output(out
, CYAssign::Precedence_
, CYNoFlags
); 
 645         out 
<< ',' << '\n' << *next_
; 
 650 void CYRegEx::Output(CYOutput 
&out
, CYFlags flags
) const { 
 654 void CYReturn::Output(CYOutput 
&out
, CYFlags flags
) const { 
 657         out 
<< ' ' << *value_
; 
 661 void CYRubyBlock::Output(CYOutput 
&out
, CYFlags flags
) const { 
 662     call_
->Output(out
, CYLeft(flags
)); 
 664     proc_
->Output(out
, CYRight(flags
)); 
 667 void CYRubyProc::Output(CYOutput 
&out
, CYFlags flags
) const { 
 668     // XXX: this is not outputting the parameters 
 676 void CYStatement::Multiple(CYOutput 
&out
, CYFlags flags
) const { 
 678     CYForEach (next
, this) { 
 679         bool last(next
->next_ 
== NULL
); 
 680         CYFlags 
jacks(first 
? last 
? flags 
: CYLeft(flags
) : last 
? CYRight(flags
) : CYCenter(flags
)); 
 683         next
->Output(out
, jacks
); 
 688 void CYStatement::Single(CYOutput 
&out
, CYFlags flags
) const { 
 690         return out
.Terminate(); 
 692     _assert(next_ 
== NULL
); 
 701 void CYString::Output(CYOutput 
&out
, CYFlags flags
) const { 
 702     std::ostringstream str
; 
 703     CYStringify(str
, value_
, size_
); 
 704     out 
<< str
.str().c_str(); 
 707 void CYString::PropertyName(CYOutput 
&out
) const { 
 708     if (const char *word 
= Word()) 
 714 static const char *Reserved_
[] = { 
 715     "false", "null", "true", 
 717     "break", "case", "catch", "continue", "default", 
 718     "delete", "do", "else", "finally", "for", "function", 
 719     "if", "in", "instanceof", "new", "return", "switch", 
 720     "this", "throw", "try", "typeof", "var", "void", 
 725     "class", "enum", "export", "extends", "import", "super", 
 727     "abstract", "boolean", "byte", "char", "double", "final", 
 728     "float", "goto", "int", "long", "native", "short", 
 729     "synchronized", "throws", "transient", "volatile", 
 736 const char *CYString::Word() const { 
 737     if (size_ 
== 0 || !WordStartRange_
[value_
[0]]) 
 739     for (size_t i(1); i 
!= size_
; ++i
) 
 740         if (!WordEndRange_
[value_
[i
]]) 
 742     const char *value(Value()); 
 743     for (const char **reserved(Reserved_
); *reserved 
!= NULL
; ++reserved
) 
 744         if (strcmp(*reserved
, value
) == 0) 
 749 void CYSwitch::Output(CYOutput 
&out
, CYFlags flags
) const { 
 750     out 
<< "switch" << ' ' << '(' << *value_ 
<< ')' << ' ' << '{'; 
 755 void CYThis::Output(CYOutput 
&out
, CYFlags flags
) const { 
 762 void Throw::Output(CYOutput 
&out
, CYFlags flags
) const { 
 765         out 
<< ' ' << *value_
; 
 769 void Try::Output(CYOutput 
&out
, CYFlags flags
) const { 
 776     out 
<< catch_ 
<< finally_
; 
 781 void CYTypeError::Output(CYOutput 
&out
) const { 
 785 void CYTypeLong::Output(CYOutput 
&out
) const { 
 786     out 
<< "long" << specifier_
; 
 789 void CYTypeShort::Output(CYOutput 
&out
) const { 
 790     out 
<< "short" << specifier_
; 
 793 void CYTypeSigned::Output(CYOutput 
&out
) const { 
 794     out 
<< "signed" << specifier_
; 
 797 void CYTypeUnsigned::Output(CYOutput 
&out
) const { 
 798     out 
<< "unsigned" << specifier_
; 
 801 void CYTypeVariable::Output(CYOutput 
&out
) const { 
 805 void CYTypeVoid::Output(CYOutput 
&out
) const { 
 809 void CYVar::Output(CYOutput 
&out
, CYFlags flags
) const { 
 811     declarations_
->Output(out
, flags
); 
 815 void CYVariable::Output(CYOutput 
&out
, CYFlags flags
) const { 
 819 void CYWhile::Output(CYOutput 
&out
, CYFlags flags
) const { 
 820     out 
<< "while" << '(' << *test_ 
<< ')'; 
 821     code_
->Single(out
, CYRight(flags
)); 
 824 void CYWith::Output(CYOutput 
&out
, CYFlags flags
) const { 
 825     out 
<< "with" << '(' << *scope_ 
<< ')'; 
 826     code_
->Single(out
, CYRight(flags
)); 
 829 void CYWord::ClassName(CYOutput 
&out
, bool object
) const { 
 831         out 
<< "objc_getClass("; 
 832     out 
<< '"' << Word() << '"'; 
 837 void CYWord::Output(CYOutput 
&out
) const { 
 839     if (out
.options_
.verbose_
) 
 840         out
.out_ 
<< '@' << this; 
 843 void CYWord::PropertyName(CYOutput 
&out
) const { 
 847 const char *CYWord::Word() const {