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. 
  41 #include "Context.hpp" 
  45 #include "Replace.hpp" 
  47 CYExpression 
*CYAdd::Replace(CYContext 
&context
) { 
  48     CYInfix::Replace(context
); 
  50     CYExpression 
*lhp(lhs_
->Primitive(context
)); 
  51     CYExpression 
*rhp(rhs_
->Primitive(context
)); 
  53     CYString 
*lhs(dynamic_cast<CYString 
*>(lhp
)); 
  54     CYString 
*rhs(dynamic_cast<CYString 
*>(rhp
)); 
  56     if (lhs 
!= NULL 
|| rhs 
!= NULL
) { 
  58             lhs 
= lhp
->String(context
); 
  61         } else if (rhs 
== NULL
) { 
  62             rhs 
= rhp
->String(context
); 
  67         return lhs
->Concat(context
, rhs
); 
  70     if (CYNumber 
*lhn 
= lhp
->Number(context
)) 
  71         if (CYNumber 
*rhn 
= rhp
->Number(context
)) 
  72             return $
D(lhn
->Value() + rhn
->Value()); 
  77 CYExpression 
*CYAddressOf::Replace(CYContext 
&context
) { 
  78     CYPrefix::Replace(context
); 
  79     return $
C0($
M(rhs_
, $
S("$cya"))); 
  82 void CYArgument::Replace(CYContext 
&context
) { $
T() 
  83     context
.Replace(value_
); 
  84     next_
->Replace(context
); 
  87 CYExpression 
*CYArray::Replace(CYContext 
&context
) { 
  88     elements_
->Replace(context
); 
  92 CYExpression 
*CYArrayComprehension::Replace(CYContext 
&context
) { 
  93     CYVariable 
*cyv($
V("$cyv")); 
  95     return $
C0($
F(NULL
, $
P1("$cyv", comprehensions_
->Parameters(context
)), $$
->* 
  96         $
E($ 
CYAssign(cyv
, $ 
CYArray()))->* 
  97         comprehensions_
->Replace(context
, $
E($
C1($
M(cyv
, $
S("push")), expression_
)))->* 
 102 CYExpression 
*CYAssignment::Replace(CYContext 
&context
) { 
 103     context
.Replace(lhs_
); 
 104     context
.Replace(rhs_
); 
 108 CYStatement 
*CYBlock::Replace(CYContext 
&context
) { 
 109     statements_ 
= statements_
->ReplaceAll(context
); 
 110     if (statements_ 
== NULL
) 
 115 CYStatement 
*CYBreak::Replace(CYContext 
&context
) { 
 119 CYExpression 
*CYCall::Replace(CYContext 
&context
) { 
 120     context
.Replace(function_
); 
 121     arguments_
->Replace(context
); 
 128 void Catch::Replace(CYContext 
&context
) { $
T() 
 129     code_
.Replace(context
); 
 134 void CYClause::Replace(CYContext 
&context
) { $
T() 
 135     context
.Replace(case_
); 
 136     statements_ 
= statements_
->ReplaceAll(context
); 
 137     next_
->Replace(context
); 
 140 CYStatement 
*CYComment::Replace(CYContext 
&context
) { 
 144 CYExpression 
*CYCompound::Replace(CYContext 
&context
) { 
 145     expressions_ 
= expressions_
->ReplaceAll(context
); 
 146     return expressions_ 
== NULL 
? NULL 
: this; 
 149 CYFunctionParameter 
*CYComprehension::Parameters(CYContext 
&context
) const { $
T(NULL
) 
 150     CYFunctionParameter 
*next(next_
->Parameters(context
)); 
 151     if (CYFunctionParameter 
*parameter 
= Parameter(context
)) { 
 152         parameter
->SetNext(next
); 
 158 CYStatement 
*CYComprehension::Replace(CYContext 
&context
, CYStatement 
*statement
) const { 
 159     return next_ 
== NULL 
? statement 
: next_
->Replace(context
, statement
); 
 162 CYExpression 
*CYCondition::Replace(CYContext 
&context
) { 
 163     context
.Replace(test_
); 
 164     context
.Replace(true_
); 
 165     context
.Replace(false_
); 
 169 CYStatement 
*CYContinue::Replace(CYContext 
&context
) { 
 173 CYAssignment 
*CYDeclaration::Assignment(CYContext 
&context
) { 
 174     CYExpression 
*variable(Replace(context
)); 
 175     return initialiser_ 
== NULL 
? NULL 
: $ 
CYAssign(variable
, initialiser_
); 
 178 CYExpression 
*CYDeclaration::ForEachIn(CYContext 
&context
) { 
 179     return $ 
CYVariable(identifier_
); 
 182 CYExpression 
*CYDeclaration::Replace(CYContext 
&context
) { 
 183     CYIdentifier 
*identifier(identifier_
->Replace(context
)); 
 184     context
.scope_
->internal_
.insert(CYIdentifierAddressFlagsMap::value_type(identifier
, CYIdentifierVariable
)); 
 185     return $ 
CYVariable(identifier
); 
 188 CYProperty 
*CYDeclarations::Property(CYContext 
&context
) { $
T(NULL
) 
 189     return $ 
CYProperty(declaration_
->identifier_
, declaration_
->initialiser_ 
?: $U
, next_
->Property(context
)); 
 192 CYCompound 
*CYDeclarations::Replace(CYContext 
&context
) { 
 193     CYCompound 
*compound
; 
 194     if (next_ 
== NULL
) compound
: 
 195         compound 
= $ 
CYCompound(); 
 197         compound 
= next_
->Replace(context
); 
 198         if (compound 
== NULL
) 
 202     if (CYAssignment 
*assignment 
= declaration_
->Assignment(context
)) 
 203         compound
->AddPrev(assignment
); 
 207 CYExpression 
*CYDirectMember::Replace(CYContext 
&context
) { 
 212 CYStatement 
*CYDoWhile::Replace(CYContext 
&context
) { 
 213     context
.Replace(test_
); 
 214     context
.Replace(code_
); 
 218 void CYElement::Replace(CYContext 
&context
) { $
T() 
 219     context
.Replace(value_
); 
 220     next_
->Replace(context
); 
 223 CYStatement 
*CYEmpty::Collapse(CYContext 
&context
) { 
 227 CYStatement 
*CYEmpty::Replace(CYContext 
&context
) { 
 231 CYStatement 
*CYExpress::Collapse(CYContext 
&context
) { 
 232     if (CYExpress 
*express 
= dynamic_cast<CYExpress 
*>(next_
)) { 
 233         CYCompound 
*next(dynamic_cast<CYCompound 
*>(express
->expression_
)); 
 235             next 
= $ 
CYCompound(express
->expression_
); 
 236         next
->AddPrev(expression_
); 
 238         SetNext(express
->next_
); 
 244 CYStatement 
*CYExpress::Replace(CYContext 
&context
) { 
 245     context
.Replace(expression_
); 
 246     if (expression_ 
== NULL
) 
 251 CYExpression 
*CYExpression::ClassName(CYContext 
&context
, bool object
) { 
 255 CYExpression 
*CYExpression::ForEachIn(CYContext 
&context
) { 
 259 CYExpression 
*CYExpression::ReplaceAll(CYContext 
&context
) { $
T(NULL
) 
 260     CYExpression 
*replace(this); 
 261     context
.Replace(replace
); 
 263     if (CYExpression 
*next 
= next_
->ReplaceAll(context
)) 
 264         replace
->SetNext(next
); 
 266         replace
->SetNext(next_
); 
 271 CYNumber 
*CYFalse::Number(CYContext 
&context
) { 
 275 CYString 
*CYFalse::String(CYContext 
&context
) { 
 279 void CYFinally::Replace(CYContext 
&context
) { $
T() 
 280     code_
.Replace(context
); 
 283 CYStatement 
*CYFor::Replace(CYContext 
&context
) { 
 284     context
.Replace(initialiser_
); 
 285     context
.Replace(test_
); 
 286     context
.Replace(increment_
); 
 287     context
.Replace(code_
); 
 291 CYStatement 
*CYForIn::Replace(CYContext 
&context
) { 
 292     // XXX: this actually might need a prefix statement 
 293     context
.Replace(initialiser_
); 
 294     context
.Replace(set_
); 
 295     context
.Replace(code_
); 
 299 CYFunctionParameter 
*CYForInComprehension::Parameter(CYContext 
&context
) const { 
 300     return $ 
CYFunctionParameter(name_
); 
 303 CYStatement 
*CYForInComprehension::Replace(CYContext 
&context
, CYStatement 
*statement
) const { 
 304     return $ 
CYForIn($ 
CYVariable(name_
), set_
, CYComprehension::Replace(context
, statement
)); 
 307 CYStatement 
*CYForEachIn::Replace(CYContext 
&context
) { 
 308     CYVariable 
*cys($
V("$cys")), *cyt($
V("$cyt")); 
 310     return $ 
CYLet($
L2($
L($
I("$cys"), set_
), $
L($
I("$cyt"))), $$
->* 
 311         $ 
CYForIn(cyt
, cys
, $ 
CYBlock($$
->* 
 312             $
E($ 
CYAssign(initialiser_
->ForEachIn(context
), $
M(cys
, cyt
)))->* 
 318 CYFunctionParameter 
*CYForEachInComprehension::Parameter(CYContext 
&context
) const { 
 319     return $ 
CYFunctionParameter(name_
); 
 322 CYStatement 
*CYForEachInComprehension::Replace(CYContext 
&context
, CYStatement 
*statement
) const { 
 323     CYVariable 
*cys($
V("$cys")), *name($ 
CYVariable(name_
)); 
 325     return $
E($
C0($
F(NULL
, $
P1("$cys"), $$
->* 
 326         $
E($ 
CYAssign(cys
, set_
))->* 
 327         $ 
CYForIn(name
, cys
, $ 
CYBlock($$
->* 
 328             $
E($ 
CYAssign(name
, $
M(cys
, name
)))->* 
 329             CYComprehension::Replace(context
, statement
) 
 334 void CYFunction::Inject(CYContext 
&context
) { 
 335     name_ 
= name_
->Replace(context
); 
 336     context
.scope_
->internal_
.insert(CYIdentifierAddressFlagsMap::value_type(name_
, CYIdentifierOther
)); 
 339 void CYFunction::Replace_(CYContext 
&context
, bool outer
) { 
 343     parent_ 
= context
.scope_
; 
 344     context
.scope_ 
= this; 
 346     if (!outer 
&& name_ 
!= NULL
) 
 349     parameters_
->Replace(context
); 
 350     code_
.Replace(context
); 
 352     context
.scope_ 
= parent_
; 
 353     Scope(context
, code_
.statements_
); 
 356 CYExpression 
*CYFunctionExpression::Replace(CYContext 
&context
) { 
 357     Replace_(context
, false); 
 361 void CYFunctionParameter::Replace(CYContext 
&context
) { $
T() 
 362     name_ 
= name_
->Replace(context
); 
 363     context
.scope_
->internal_
.insert(CYIdentifierAddressFlagsMap::value_type(name_
, CYIdentifierArgument
)); 
 364     next_
->Replace(context
); 
 367 CYStatement 
*CYFunctionStatement::Replace(CYContext 
&context
) { 
 368     Replace_(context
, true); 
 372 CYIdentifier 
*CYIdentifier::Replace(CYContext 
&context
) { 
 373     if (replace_ 
!= NULL
) 
 376     CYIdentifierValueSet 
&identifiers(context
.scope_
->identifiers_
); 
 377     std::pair
<CYIdentifierValueSet::iterator
, bool> insert(identifiers
.insert(this)); 
 379         return *insert
.first
; 
 385 CYStatement 
*CYIf::Replace(CYContext 
&context
) { 
 386     context
.Replace(test_
); 
 387     context
.Replace(true_
); 
 388     context
.Replace(false_
); 
 392 CYFunctionParameter 
*CYIfComprehension::Parameter(CYContext 
&context
) const { 
 396 CYStatement 
*CYIfComprehension::Replace(CYContext 
&context
, CYStatement 
*statement
) const { 
 397     return $ 
CYIf(test_
, CYComprehension::Replace(context
, statement
)); 
 400 CYExpression 
*CYIndirect::Replace(CYContext 
&context
) { 
 401     CYPrefix::Replace(context
); 
 402     return $
M(rhs_
, $
S("$cyi")); 
 405 CYExpression 
*CYIndirectMember::Replace(CYContext 
&context
) { 
 407     return $
M($ 
CYIndirect(object_
), property_
); 
 410 CYExpression 
*CYInfix::Replace(CYContext 
&context
) { 
 411     context
.Replace(lhs_
); 
 412     context
.Replace(rhs_
); 
 416 CYStatement 
*CYLabel::Replace(CYContext 
&context
) { 
 417     context
.Replace(statement_
); 
 421 CYStatement 
*CYLet::Replace(CYContext 
&context
) { 
 422     return $ 
CYWith($ 
CYObject(declarations_
->Property(context
)), &code_
); 
 425 void CYMember::Replace_(CYContext 
&context
) { 
 426     context
.Replace(object_
); 
 427     context
.Replace(property_
); 
 430 CYExpression 
*CYNew::Replace(CYContext 
&context
) { 
 431     context
.Replace(constructor_
); 
 432     arguments_
->Replace(context
); 
 436 CYNumber 
*CYNull::Number(CYContext 
&context
) { 
 440 CYString 
*CYNull::String(CYContext 
&context
) { 
 444 CYNumber 
*CYNumber::Number(CYContext 
&context
) { 
 448 CYString 
*CYNumber::String(CYContext 
&context
) { 
 449     // XXX: there is a precise algorithm for this 
 450     return $
S(apr_psprintf(context
.pool_
, "%.17g", Value())); 
 453 CYExpression 
*CYObject::Replace(CYContext 
&context
) { 
 454     properties_
->Replace(context
); 
 458 CYExpression 
*CYPostfix::Replace(CYContext 
&context
) { 
 459     context
.Replace(lhs_
); 
 463 CYExpression 
*CYPrefix::Replace(CYContext 
&context
) { 
 464     context
.Replace(rhs_
); 
 468 void CYProgram::Replace(CYContext 
&context
) { 
 469     parent_ 
= context
.scope_
; 
 470     CYProgram 
*program(context
.program_
); 
 472     context
.scope_ 
= this; 
 473     context
.program_ 
= this; 
 475     statements_ 
= statements_
->ReplaceAll(context
); 
 477     context
.scope_ 
= parent_
; 
 478     Scope(context
, statements_
); 
 479     context
.program_ 
= program
; 
 483     // XXX: totalling the probable occurrences and sorting by them would improve the result 
 484     for (CYIdentifierAddressVector::const_iterator 
i(rename_
.begin()); i 
!= rename_
.end(); ++i
, ++offset
) { 
 487         if (context
.options_
.verbose_
) 
 488             name 
= apr_psprintf(context
.pool_
, "$%"APR_SIZE_T_FMT
"", offset
); 
 494             unsigned position(7), local(offset 
+ 1); 
 497                 unsigned index(local 
% 53); 
 499                 id
[--position
] = index 
== 0 ? '0' : index 
< 27 ? index 
- 1 + 'a' : index 
- 27 + 'A'; 
 500             } while (local 
!= 0); 
 502             if (external_
.find(id 
+ position
) != external_
.end()) { 
 507             name 
= apr_pstrmemdup(context
.pool_
, id 
+ position
, 7 - position
); 
 508             // XXX: at some point, this could become a keyword 
 511         for (CYIdentifier 
*identifier(*i
); identifier 
!= NULL
; identifier 
= identifier
->next_
) 
 512             identifier
->Set(name
); 
 516 void CYProperty::Replace(CYContext 
&context
) { $
T() 
 517     context
.Replace(value_
); 
 518     next_
->Replace(context
); 
 521 CYStatement 
*CYReturn::Replace(CYContext 
&context
) { 
 522     context
.Replace(value_
); 
 526 void CYScope::Add(CYContext 
&context
, CYIdentifierAddressVector 
&external
) { 
 527     for (CYIdentifierAddressVector::const_iterator 
i(external
.begin()); i 
!= external
.end(); ++i
) { 
 528         std::pair
<CYIdentifierAddressSet::iterator
, bool> insert(identifiers_
.insert(*i
)); 
 530             (*i
)->replace_ 
= *insert
.first
; 
 534 void CYScope::Scope(CYContext 
&context
, CYStatement 
*&statements
) { 
 535     CYIdentifierAddressVector external
; 
 537     for (CYIdentifierValueSet::const_iterator 
i(identifiers_
.begin()); i 
!= identifiers_
.end(); ++i
) 
 538         if (internal_
.find(*i
) == internal_
.end()) 
 539             external
.push_back(*i
); 
 541     CYDeclarations 
*last(NULL
), *curr(NULL
); 
 542     CYProgram 
*program(context
.program_
); 
 544     // XXX: we don't want to do this in order, we want to sort it by probable occurrence 
 545     for (CYIdentifierAddressFlagsMap::const_iterator 
i(internal_
.begin()); i 
!= internal_
.end(); ++i
) { 
 546         if (program 
!= NULL 
&& i
->second 
!= CYIdentifierMagic
) { 
 547             if (program
->rename_
.size() <= offset_
) 
 548                 program
->rename_
.resize(offset_ 
+ 1); 
 549             CYIdentifier 
*&identifier(program
->rename_
[offset_
++]); 
 550             i
->first
->SetNext(identifier
); 
 551             identifier 
= i
->first
; 
 554         if (i
->second 
== CYIdentifierVariable
) { 
 555             CYDeclarations 
*next($ 
CYDeclarations($ 
CYDeclaration(i
->first
))); 
 565         CYVar 
*var($ 
CYVar(last
)); 
 566         var
->SetNext(statements
); 
 570     if (parent_ 
!= NULL
) { 
 571         if (parent_
->offset_ 
< offset_
) 
 572             parent_
->offset_ 
= offset_
; 
 573         parent_
->Add(context
, external
); 
 574     } else if (program 
!= NULL
) 
 575         for (CYIdentifierAddressVector::const_iterator 
i(external
.begin()); i 
!= external
.end(); ++i
) 
 576             program
->external_
.insert((*i
)->Word()); 
 579 CYStatement 
*CYStatement::Collapse(CYContext 
&context
) { 
 583 CYStatement 
*CYStatement::ReplaceAll(CYContext 
&context
) { $
T(NULL
) 
 584     CYStatement 
*replace(this); 
 585     context
.Replace(replace
); 
 586     replace
->SetNext(next_
->ReplaceAll(context
)); 
 587     return replace
->Collapse(context
); 
 590 CYString 
*CYString::Concat(CYContext 
&context
, CYString 
*rhs
) const { 
 591     size_t size(size_ 
+ rhs
->size_
); 
 592     char *value(new(context
.pool_
) char[size 
+ 1]); 
 593     memcpy(value
, value_
, size_
); 
 594     memcpy(value 
+ size_
, rhs
->value_
, rhs
->size_
); 
 596     return $
S(value
, size
); 
 599 CYNumber 
*CYString::Number(CYContext 
&context
) { 
 600     // XXX: there is a precise algorithm for this 
 604 CYString 
*CYString::String(CYContext 
&context
) { 
 608 CYStatement 
*CYSwitch::Replace(CYContext 
&context
) { 
 609     context
.Replace(value_
); 
 610     clauses_
->Replace(context
); 
 614 CYExpression 
*CYThis::Replace(CYContext 
&context
) { 
 621 CYStatement 
*Throw::Replace(CYContext 
&context
) { 
 622     context
.Replace(value_
); 
 628 CYExpression 
*CYTrivial::Replace(CYContext 
&context
) { 
 632 CYNumber 
*CYTrue::Number(CYContext 
&context
) { 
 636 CYString 
*CYTrue::String(CYContext 
&context
) { 
 643 CYStatement 
*Try::Replace(CYContext 
&context
) { 
 644     code_
.Replace(context
); 
 645     catch_
->Replace(context
); 
 646     finally_
->Replace(context
); 
 652 CYStatement 
*CYVar::Replace(CYContext 
&context
) { 
 653     return $
E(declarations_
->Replace(context
)); 
 656 CYExpression 
*CYVariable::Replace(CYContext 
&context
) { 
 657     name_ 
= name_
->Replace(context
); 
 661 CYStatement 
*CYWhile::Replace(CYContext 
&context
) { 
 662     context
.Replace(test_
); 
 663     context
.Replace(code_
); 
 667 CYStatement 
*CYWith::Replace(CYContext 
&context
) { 
 668     context
.Replace(scope_
); 
 669     context
.Replace(code_
); 
 673 CYExpression 
*CYWord::ClassName(CYContext 
&context
, bool object
) { 
 674     CYString 
*name($
S(this)); 
 676         return $
C1($
V("objc_getClass"), name
);