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::Replace_(CYContext
&context
) {
335 parent_
= context
.scope_
;
336 context
.scope_
= this;
338 parameters_
->Replace(context
);
339 code_
.Replace(context
);
341 context
.scope_
= parent_
;
342 Scope(context
, code_
.statements_
);
345 CYExpression
*CYFunctionExpression::Replace(CYContext
&context
) {
350 void CYFunctionParameter::Replace(CYContext
&context
) { $
T()
351 name_
= name_
->Replace(context
);
352 context
.scope_
->internal_
.insert(CYIdentifierAddressFlagsMap::value_type(name_
, CYIdentifierArgument
));
353 next_
->Replace(context
);
356 CYStatement
*CYFunctionStatement::Replace(CYContext
&context
) {
361 CYIdentifier
*CYIdentifier::Replace(CYContext
&context
) {
362 if (replace_
!= NULL
)
365 CYIdentifierValueSet
&identifiers(context
.scope_
->identifiers_
);
366 std::pair
<CYIdentifierValueSet::iterator
, bool> insert(identifiers
.insert(this));
368 return *insert
.first
;
374 CYStatement
*CYIf::Replace(CYContext
&context
) {
375 context
.Replace(test_
);
376 context
.Replace(true_
);
377 context
.Replace(false_
);
381 CYFunctionParameter
*CYIfComprehension::Parameter(CYContext
&context
) const {
385 CYStatement
*CYIfComprehension::Replace(CYContext
&context
, CYStatement
*statement
) const {
386 return $
CYIf(test_
, CYComprehension::Replace(context
, statement
));
389 CYExpression
*CYIndirect::Replace(CYContext
&context
) {
390 CYPrefix::Replace(context
);
391 return $
M(rhs_
, $
S("$cyi"));
394 CYExpression
*CYIndirectMember::Replace(CYContext
&context
) {
396 return $
M($
CYIndirect(object_
), property_
);
399 CYExpression
*CYInfix::Replace(CYContext
&context
) {
400 context
.Replace(lhs_
);
401 context
.Replace(rhs_
);
405 CYStatement
*CYLabel::Replace(CYContext
&context
) {
406 context
.Replace(statement_
);
410 CYStatement
*CYLet::Replace(CYContext
&context
) {
411 return $
CYWith($
CYObject(declarations_
->Property(context
)), &code_
);
414 void CYMember::Replace_(CYContext
&context
) {
415 context
.Replace(object_
);
416 context
.Replace(property_
);
419 CYExpression
*CYNew::Replace(CYContext
&context
) {
420 context
.Replace(constructor_
);
421 arguments_
->Replace(context
);
425 CYNumber
*CYNull::Number(CYContext
&context
) {
429 CYString
*CYNull::String(CYContext
&context
) {
433 CYNumber
*CYNumber::Number(CYContext
&context
) {
437 CYString
*CYNumber::String(CYContext
&context
) {
438 // XXX: there is a precise algorithm for this
439 return $
S(apr_psprintf(context
.pool_
, "%.17g", Value()));
442 CYExpression
*CYObject::Replace(CYContext
&context
) {
443 properties_
->Replace(context
);
447 CYExpression
*CYPostfix::Replace(CYContext
&context
) {
448 context
.Replace(lhs_
);
452 CYExpression
*CYPrefix::Replace(CYContext
&context
) {
453 context
.Replace(rhs_
);
457 void CYProgram::Replace(CYContext
&context
) {
458 parent_
= context
.scope_
;
459 context
.scope_
= this;
460 statements_
= statements_
->ReplaceAll(context
);
461 context
.scope_
= parent_
;
462 Scope(context
, statements_
);
465 void CYProperty::Replace(CYContext
&context
) { $
T()
466 context
.Replace(value_
);
467 next_
->Replace(context
);
470 CYStatement
*CYReturn::Replace(CYContext
&context
) {
471 context
.Replace(value_
);
475 void CYScope::Add(CYContext
&context
, CYIdentifierAddressSet
&external
) {
476 for (CYIdentifierAddressSet::const_iterator
i(external
.begin()); i
!= external
.end(); ++i
) {
477 std::pair
<CYIdentifierAddressSet::iterator
, bool> insert(identifiers_
.insert(*i
));
479 (*i
)->replace_
= *insert
.first
;
483 void CYScope::Scope(CYContext
&context
, CYStatement
*&statements
) {
484 CYIdentifierAddressSet external
;
486 if (context
.options_
.verbose_
)
487 std::cout
<< this << ':';
489 CYDeclarations
*last(NULL
), *curr(NULL
);
491 for (CYIdentifierValueSet::const_iterator
i(identifiers_
.begin()); i
!= identifiers_
.end(); ++i
)
492 if (internal_
.find(*i
) == internal_
.end()) {
493 if (context
.options_
.verbose_
)
494 std::cout
<< ' ' << (*i
)->Word() << '@' << static_cast<const CYWord
*>(*i
);
497 if (context
.options_
.verbose_
) {
498 std::cout
<< ' ' << offset_
<< ':' << (*i
)->Word() << '@' << static_cast<const CYWord
*>(*i
);
499 (*i
)->Set(apr_psprintf(context
.pool_
, "$%u", offset_
++));
501 (*i
)->Set(apr_psprintf(context
.pool_
, "$%u", offset_
++));
504 CYDeclarations
*next($
CYDeclarations($
CYDeclaration(*i
)));
512 if (context
.options_
.verbose_
)
513 std::cout
<< " ->" << parent_
<< std::endl
;
516 CYVar
*var($
CYVar(last
));
517 var
->SetNext(statements
);
521 if (parent_
!= NULL
) {
522 if (parent_
->offset_
< offset_
)
523 parent_
->offset_
= offset_
;
524 parent_
->Add(context
, external
);
528 CYStatement
*CYStatement::Collapse(CYContext
&context
) {
532 CYStatement
*CYStatement::ReplaceAll(CYContext
&context
) { $
T(NULL
)
533 CYStatement
*replace(this);
534 context
.Replace(replace
);
535 replace
->SetNext(next_
->ReplaceAll(context
));
536 return replace
->Collapse(context
);
539 CYString
*CYString::Concat(CYContext
&context
, CYString
*rhs
) const {
540 size_t size(size_
+ rhs
->size_
);
541 char *value(new(context
.pool_
) char[size
+ 1]);
542 memcpy(value
, value_
, size_
);
543 memcpy(value
+ size_
, rhs
->value_
, rhs
->size_
);
545 return $
S(value
, size
);
548 CYNumber
*CYString::Number(CYContext
&context
) {
549 // XXX: there is a precise algorithm for this
553 CYString
*CYString::String(CYContext
&context
) {
557 CYStatement
*CYSwitch::Replace(CYContext
&context
) {
558 context
.Replace(value_
);
559 clauses_
->Replace(context
);
563 CYExpression
*CYThis::Replace(CYContext
&context
) {
570 CYStatement
*Throw::Replace(CYContext
&context
) {
571 context
.Replace(value_
);
577 CYExpression
*CYTrivial::Replace(CYContext
&context
) {
581 CYNumber
*CYTrue::Number(CYContext
&context
) {
585 CYString
*CYTrue::String(CYContext
&context
) {
592 CYStatement
*Try::Replace(CYContext
&context
) {
593 code_
.Replace(context
);
594 catch_
->Replace(context
);
595 finally_
->Replace(context
);
601 CYStatement
*CYVar::Replace(CYContext
&context
) {
602 return $
E(declarations_
->Replace(context
));
605 CYExpression
*CYVariable::Replace(CYContext
&context
) {
606 name_
= name_
->Replace(context
);
610 CYStatement
*CYWhile::Replace(CYContext
&context
) {
611 context
.Replace(test_
);
612 context
.Replace(code_
);
616 CYStatement
*CYWith::Replace(CYContext
&context
) {
617 context
.Replace(scope_
);
618 context
.Replace(code_
);
622 CYExpression
*CYWord::ClassName(CYContext
&context
, bool object
) {
623 CYString
*name($
S(this));
625 return $
C1($
V("objc_getClass"), name
);