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 "Replace.hpp"
45 CYExpression
*CYAdd::Replace(CYContext
&context
) {
46 CYInfix::Replace(context
);
48 CYExpression
*lhp(lhs_
->Primitive(context
));
49 CYExpression
*rhp(rhs_
->Primitive(context
));
51 CYString
*lhs(dynamic_cast<CYString
*>(lhp
));
52 CYString
*rhs(dynamic_cast<CYString
*>(rhp
));
54 if (lhs
!= NULL
|| rhs
!= NULL
) {
56 lhs
= lhp
->String(context
);
59 } else if (rhs
== NULL
) {
60 rhs
= rhp
->String(context
);
65 return lhs
->Concat(context
, rhs
);
68 if (CYNumber
*lhn
= lhp
->Number(context
))
69 if (CYNumber
*rhn
= rhp
->Number(context
))
70 return $
D(lhn
->Value() + rhn
->Value());
75 CYExpression
*CYAddressOf::Replace(CYContext
&context
) {
76 CYPrefix::Replace(context
);
77 return $
C0($
M(rhs_
, $
S("$cya")));
80 void CYArgument::Replace(CYContext
&context
) { $
T()
81 context
.Replace(value_
);
82 next_
->Replace(context
);
85 CYExpression
*CYArray::Replace(CYContext
&context
) {
86 elements_
->Replace(context
);
90 CYExpression
*CYArrayComprehension::Replace(CYContext
&context
) {
91 CYVariable
*cyv($
V("$cyv"));
93 return $
C0($
F(NULL
, $
P1("$cyv", comprehensions_
->Parameters(context
)), $$
->*
94 $
E($
CYAssign(cyv
, $
CYArray()))->*
95 comprehensions_
->Replace(context
, $
E($
C1($
M(cyv
, $
S("push")), expression_
)))->*
100 CYExpression
*CYAssignment::Replace(CYContext
&context
) {
101 context
.Replace(lhs_
);
102 context
.Replace(rhs_
);
106 CYStatement
*CYBlock::Replace(CYContext
&context
) {
107 statements_
= statements_
->ReplaceAll(context
);
108 if (statements_
== NULL
)
113 CYStatement
*CYBreak::Replace(CYContext
&context
) {
117 CYExpression
*CYCall::Replace(CYContext
&context
) {
118 context
.Replace(function_
);
119 arguments_
->Replace(context
);
126 void Catch::Replace(CYContext
&context
) { $
T()
127 code_
.Replace(context
);
132 void CYClause::Replace(CYContext
&context
) { $
T()
133 context
.Replace(case_
);
134 statements_
= statements_
->ReplaceAll(context
);
135 next_
->Replace(context
);
138 CYStatement
*CYComment::Replace(CYContext
&context
) {
142 CYExpression
*CYCompound::Replace(CYContext
&context
) {
143 expressions_
= expressions_
->ReplaceAll(context
);
144 return expressions_
== NULL
? NULL
: this;
147 CYFunctionParameter
*CYComprehension::Parameters(CYContext
&context
) const { $
T(NULL
)
148 CYFunctionParameter
*next(next_
->Parameters(context
));
149 if (CYFunctionParameter
*parameter
= Parameter(context
)) {
150 parameter
->SetNext(next
);
156 CYStatement
*CYComprehension::Replace(CYContext
&context
, CYStatement
*statement
) const {
157 return next_
== NULL
? statement
: next_
->Replace(context
, statement
);
160 CYExpression
*CYCondition::Replace(CYContext
&context
) {
161 context
.Replace(test_
);
162 context
.Replace(true_
);
163 context
.Replace(false_
);
167 CYStatement
*CYContinue::Replace(CYContext
&context
) {
171 CYAssignment
*CYDeclaration::Assignment(CYContext
&context
) {
172 CYExpression
*variable(Replace(context
));
173 return initialiser_
== NULL
? NULL
: $
CYAssign(variable
, initialiser_
);
176 CYExpression
*CYDeclaration::ForEachIn(CYContext
&context
) {
177 return $
CYVariable(identifier_
);
180 CYExpression
*CYDeclaration::Replace(CYContext
&context
) {
181 context
.Replace(identifier_
);
182 context
.scope_
->Declare(context
, identifier_
, CYIdentifierVariable
);
183 return $
CYVariable(identifier_
);
186 CYProperty
*CYDeclarations::Property(CYContext
&context
) { $
T(NULL
)
187 return $
CYProperty(declaration_
->identifier_
, declaration_
->initialiser_
?: $U
, next_
->Property(context
));
190 CYCompound
*CYDeclarations::Replace(CYContext
&context
) {
191 CYCompound
*compound
;
192 if (next_
== NULL
) compound
:
193 compound
= $
CYCompound();
195 compound
= next_
->Replace(context
);
196 if (compound
== NULL
)
200 if (CYAssignment
*assignment
= declaration_
->Assignment(context
))
201 compound
->AddPrev(assignment
);
205 CYExpression
*CYDirectMember::Replace(CYContext
&context
) {
210 CYStatement
*CYDoWhile::Replace(CYContext
&context
) {
211 context
.Replace(test_
);
212 context
.Replace(code_
);
216 void CYElement::Replace(CYContext
&context
) { $
T()
217 context
.Replace(value_
);
218 next_
->Replace(context
);
221 CYStatement
*CYEmpty::Collapse(CYContext
&context
) {
225 CYStatement
*CYEmpty::Replace(CYContext
&context
) {
229 CYStatement
*CYExpress::Collapse(CYContext
&context
) {
230 if (CYExpress
*express
= dynamic_cast<CYExpress
*>(next_
)) {
231 CYCompound
*next(dynamic_cast<CYCompound
*>(express
->expression_
));
233 next
= $
CYCompound(express
->expression_
);
234 next
->AddPrev(expression_
);
236 SetNext(express
->next_
);
242 CYStatement
*CYExpress::Replace(CYContext
&context
) {
243 context
.Replace(expression_
);
244 if (expression_
== NULL
)
249 CYExpression
*CYExpression::ClassName(CYContext
&context
, bool object
) {
253 CYExpression
*CYExpression::ForEachIn(CYContext
&context
) {
257 CYExpression
*CYExpression::ReplaceAll(CYContext
&context
) { $
T(NULL
)
258 CYExpression
*replace(this);
259 context
.Replace(replace
);
261 if (CYExpression
*next
= next_
->ReplaceAll(context
))
262 replace
->SetNext(next
);
264 replace
->SetNext(next_
);
269 CYNumber
*CYFalse::Number(CYContext
&context
) {
273 CYString
*CYFalse::String(CYContext
&context
) {
277 void CYFinally::Replace(CYContext
&context
) { $
T()
278 code_
.Replace(context
);
281 CYStatement
*CYFor::Replace(CYContext
&context
) {
282 context
.Replace(initialiser_
);
283 context
.Replace(test_
);
284 context
.Replace(increment_
);
285 context
.Replace(code_
);
289 CYStatement
*CYForIn::Replace(CYContext
&context
) {
290 // XXX: this actually might need a prefix statement
291 context
.Replace(initialiser_
);
292 context
.Replace(set_
);
293 context
.Replace(code_
);
297 CYFunctionParameter
*CYForInComprehension::Parameter(CYContext
&context
) const {
298 return $
CYFunctionParameter(name_
);
301 CYStatement
*CYForInComprehension::Replace(CYContext
&context
, CYStatement
*statement
) const {
302 return $
CYForIn($
CYVariable(name_
), set_
, CYComprehension::Replace(context
, statement
));
305 CYStatement
*CYForEachIn::Replace(CYContext
&context
) {
306 CYVariable
*cys($
V("$cys")), *cyt($
V("$cyt"));
308 return $
CYLet($
L2($
L($
I("$cys"), set_
), $
L($
I("$cyt"))), $$
->*
309 $
CYForIn(cyt
, cys
, $
CYBlock($$
->*
310 $
E($
CYAssign(initialiser_
->ForEachIn(context
), $
M(cys
, cyt
)))->*
316 CYFunctionParameter
*CYForEachInComprehension::Parameter(CYContext
&context
) const {
317 return $
CYFunctionParameter(name_
);
320 CYStatement
*CYForEachInComprehension::Replace(CYContext
&context
, CYStatement
*statement
) const {
321 CYVariable
*cys($
V("$cys")), *name($
CYVariable(name_
));
323 return $
E($
C0($
F(NULL
, $
P1("$cys"), $$
->*
324 $
E($
CYAssign(cys
, set_
))->*
325 $
CYForIn(name
, cys
, $
CYBlock($$
->*
326 $
E($
CYAssign(name
, $
M(cys
, name
)))->*
327 CYComprehension::Replace(context
, statement
)
332 void CYFunction::Inject(CYContext
&context
) {
333 context
.Replace(name_
);
334 context
.scope_
->Declare(context
, name_
, CYIdentifierOther
);
337 void CYFunction::Replace_(CYContext
&context
, bool outer
) {
341 parent_
= context
.scope_
;
342 context
.scope_
= this;
344 if (!outer
&& name_
!= NULL
)
347 parameters_
->Replace(context
);
348 code_
.Replace(context
);
350 context
.scope_
= parent_
;
351 Scope(context
, code_
.statements_
);
354 CYExpression
*CYFunctionExpression::Replace(CYContext
&context
) {
355 Replace_(context
, false);
359 void CYFunctionParameter::Replace(CYContext
&context
) { $
T()
360 name_
= name_
->Replace(context
);
361 context
.scope_
->Declare(context
, name_
, CYIdentifierArgument
);
362 next_
->Replace(context
);
365 CYStatement
*CYFunctionStatement::Replace(CYContext
&context
) {
366 Replace_(context
, true);
370 CYIdentifier
*CYIdentifier::Replace(CYContext
&context
) {
371 if (replace_
== NULL
)
372 replace_
= context
.scope_
->Lookup(context
, this);
376 CYStatement
*CYIf::Replace(CYContext
&context
) {
377 context
.Replace(test_
);
378 context
.Replace(true_
);
379 context
.Replace(false_
);
383 CYFunctionParameter
*CYIfComprehension::Parameter(CYContext
&context
) const {
387 CYStatement
*CYIfComprehension::Replace(CYContext
&context
, CYStatement
*statement
) const {
388 return $
CYIf(test_
, CYComprehension::Replace(context
, statement
));
391 CYExpression
*CYIndirect::Replace(CYContext
&context
) {
392 CYPrefix::Replace(context
);
393 return $
M(rhs_
, $
S("$cyi"));
396 CYExpression
*CYIndirectMember::Replace(CYContext
&context
) {
398 return $
M($
CYIndirect(object_
), property_
);
401 CYExpression
*CYInfix::Replace(CYContext
&context
) {
402 context
.Replace(lhs_
);
403 context
.Replace(rhs_
);
407 CYStatement
*CYLabel::Replace(CYContext
&context
) {
408 context
.Replace(statement_
);
412 CYStatement
*CYLet::Replace(CYContext
&context
) {
413 return $
CYWith($
CYObject(declarations_
->Property(context
)), &code_
);
416 void CYMember::Replace_(CYContext
&context
) {
417 context
.Replace(object_
);
418 context
.Replace(property_
);
421 CYExpression
*CYNew::Replace(CYContext
&context
) {
422 context
.Replace(constructor_
);
423 arguments_
->Replace(context
);
427 CYNumber
*CYNull::Number(CYContext
&context
) {
431 CYString
*CYNull::String(CYContext
&context
) {
435 CYNumber
*CYNumber::Number(CYContext
&context
) {
439 CYString
*CYNumber::String(CYContext
&context
) {
440 // XXX: there is a precise algorithm for this
441 return $
S(apr_psprintf(context
.pool_
, "%.17g", Value()));
444 CYExpression
*CYObject::Replace(CYContext
&context
) {
445 properties_
->Replace(context
);
449 CYExpression
*CYPostfix::Replace(CYContext
&context
) {
450 context
.Replace(lhs_
);
454 CYExpression
*CYPrefix::Replace(CYContext
&context
) {
455 context
.Replace(rhs_
);
459 #define MappingSet "0etnirsoalfucdphmgyvbxTwSNECAFjDLkMOIBPqzRH$_WXUVGYKQJZ"
461 void CYProgram::Replace(CYContext
&context
) {
462 parent_
= context
.scope_
;
463 CYProgram
*program(context
.program_
);
465 context
.scope_
= this;
466 context
.program_
= this;
468 statements_
= statements_
->ReplaceAll(context
);
470 context
.scope_
= parent_
;
471 context
.program_
= program
;
472 Scope(context
, statements_
);
476 CYCStringSet external
;
477 for (CYIdentifierValueSet::const_iterator
i(identifiers_
.begin()); i
!= identifiers_
.end(); ++i
)
478 external
.insert((*i
)->Word());
480 // XXX: totalling the probable occurrences and sorting by them would improve the result
481 for (CYIdentifierAddressVector::const_iterator
i(rename_
.begin()); i
!= rename_
.end(); ++i
, ++offset
) {
484 if (context
.options_
.verbose_
)
485 name
= apr_psprintf(context
.pool_
, "$%"APR_SIZE_T_FMT
"", offset
);
491 unsigned position(7), local(offset
+ 1);
494 unsigned index(local
% (sizeof(MappingSet
) - 1));
495 local
/= sizeof(MappingSet
) - 1;
496 id
[--position
] = MappingSet
[index
];
497 } while (local
!= 0);
499 if (external
.find(id
+ position
) != external
.end()) {
504 name
= apr_pstrmemdup(context
.pool_
, id
+ position
, 7 - position
);
505 // XXX: at some point, this could become a keyword
508 for (CYIdentifier
*identifier(*i
); identifier
!= NULL
; identifier
= identifier
->next_
)
509 identifier
->Set(name
);
513 void CYProperty::Replace(CYContext
&context
) { $
T()
514 context
.Replace(value_
);
515 next_
->Replace(context
);
518 CYStatement
*CYReturn::Replace(CYContext
&context
) {
519 context
.Replace(value_
);
523 void CYScope::Declare(CYContext
&context
, CYIdentifier
*identifier
, CYIdentifierFlags flags
) {
524 internal_
.insert(CYIdentifierAddressFlagsMap::value_type(identifier
, flags
));
527 CYIdentifier
*CYScope::Lookup(CYContext
&context
, CYIdentifier
*identifier
) {
528 std::pair
<CYIdentifierValueSet::iterator
, bool> insert(identifiers_
.insert(identifier
));
529 return *insert
.first
;
532 void CYScope::Merge(CYContext
&context
, CYIdentifier
*identifier
) {
533 std::pair
<CYIdentifierAddressSet::iterator
, bool> insert(identifiers_
.insert(identifier
));
534 if (!insert
.second
) {
535 if ((*insert
.first
)->offset_
< identifier
->offset_
)
536 (*insert
.first
)->offset_
= identifier
->offset_
;
537 identifier
->replace_
= *insert
.first
;
541 void CYScope::Scope(CYContext
&context
, CYStatement
*&statements
) {
542 CYDeclarations
*last(NULL
), *curr(NULL
);
543 CYProgram
*program(context
.program_
);
545 typedef std::multimap
<size_t, CYIdentifier
*> IdentifierOffsetMap
;
546 IdentifierOffsetMap offsetted
;
548 // XXX: we don't want to do this in order, we want to sort it by probable occurrence
549 for (CYIdentifierAddressFlagsMap::const_iterator
i(internal_
.begin()); i
!= internal_
.end(); ++i
) {
550 if (program
!= NULL
&& i
->second
!= CYIdentifierMagic
)
551 offsetted
.insert(IdentifierOffsetMap::value_type(i
->first
->offset_
, i
->first
));
552 if (i
->second
== CYIdentifierVariable
) {
553 CYDeclarations
*next($
CYDeclarations($
CYDeclaration(i
->first
)));
564 for (IdentifierOffsetMap::const_iterator
i(offsetted
.begin()); i
!= offsetted
.end(); ++i
) {
565 if (offset
< i
->first
)
567 if (program
->rename_
.size() <= offset
)
568 program
->rename_
.resize(offset
+ 1);
569 CYIdentifier
*&identifier(program
->rename_
[offset
++]);
570 i
->second
->SetNext(identifier
);
571 identifier
= i
->second
;
575 CYVar
*var($
CYVar(last
));
576 var
->SetNext(statements
);
580 for (CYIdentifierValueSet::const_iterator
i(identifiers_
.begin()); i
!= identifiers_
.end(); ++i
)
581 if (internal_
.find(*i
) == internal_
.end()) {
582 if ((*i
)->offset_
< offset
)
583 (*i
)->offset_
= offset
;
584 parent_
->Merge(context
, *i
);
588 CYStatement
*CYStatement::Collapse(CYContext
&context
) {
592 CYStatement
*CYStatement::ReplaceAll(CYContext
&context
) { $
T(NULL
)
593 CYStatement
*replace(this);
594 context
.Replace(replace
);
595 replace
->SetNext(next_
->ReplaceAll(context
));
596 return replace
->Collapse(context
);
599 CYString
*CYString::Concat(CYContext
&context
, CYString
*rhs
) const {
600 size_t size(size_
+ rhs
->size_
);
601 char *value(new(context
.pool_
) char[size
+ 1]);
602 memcpy(value
, value_
, size_
);
603 memcpy(value
+ size_
, rhs
->value_
, rhs
->size_
);
605 return $
S(value
, size
);
608 CYNumber
*CYString::Number(CYContext
&context
) {
609 // XXX: there is a precise algorithm for this
613 CYString
*CYString::String(CYContext
&context
) {
617 CYStatement
*CYSwitch::Replace(CYContext
&context
) {
618 context
.Replace(value_
);
619 clauses_
->Replace(context
);
623 CYExpression
*CYThis::Replace(CYContext
&context
) {
630 CYStatement
*Throw::Replace(CYContext
&context
) {
631 context
.Replace(value_
);
637 CYExpression
*CYTrivial::Replace(CYContext
&context
) {
641 CYNumber
*CYTrue::Number(CYContext
&context
) {
645 CYString
*CYTrue::String(CYContext
&context
) {
652 CYStatement
*Try::Replace(CYContext
&context
) {
653 code_
.Replace(context
);
654 catch_
->Replace(context
);
655 finally_
->Replace(context
);
661 CYStatement
*CYVar::Replace(CYContext
&context
) {
662 return $
E(declarations_
->Replace(context
));
665 CYExpression
*CYVariable::Replace(CYContext
&context
) {
666 name_
= name_
->Replace(context
);
670 CYStatement
*CYWhile::Replace(CYContext
&context
) {
671 context
.Replace(test_
);
672 context
.Replace(code_
);
676 CYStatement
*CYWith::Replace(CYContext
&context
) {
677 context
.Replace(scope_
);
678 context
.Replace(code_
);
682 CYExpression
*CYWord::ClassName(CYContext
&context
, bool object
) {
683 CYString
*name($
S(this));
685 return $
C1($
V("objc_getClass"), name
);