4d1a2be5d2cf7c5611a0b51249bb1a38e85f28bc
[cycript.git] / Replace.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
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.
11
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.
16
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/>.
19 **/
20 /* }}} */
21
22 #include <iomanip>
23
24 #include "Replace.hpp"
25 #include "Syntax.hpp"
26
27 CYFunctionExpression *CYNonLocalize(CYContext &context, CYFunctionExpression *function) {
28 function->nonlocal_ = context.nextlocal_;
29 return function;
30 }
31
32 CYFunctionExpression *CYSuperize(CYContext &context, CYFunctionExpression *function) {
33 function->super_ = context.super_;
34 return function;
35 }
36
37 static void CYImplicitReturn(CYStatement *&code) {
38 if (CYStatement *&last = CYGetLast(code))
39 last = last->Return();
40 }
41
42 CYExpression *CYAdd::Replace(CYContext &context) {
43 CYInfix::Replace(context);
44
45 CYString *lhs(dynamic_cast<CYString *>(lhs_));
46 CYString *rhs(dynamic_cast<CYString *>(rhs_));
47
48 if (lhs != NULL || rhs != NULL) {
49 if (lhs == NULL) {
50 lhs = lhs_->String(context);
51 if (lhs == NULL)
52 return this;
53 } else if (rhs == NULL) {
54 rhs = rhs_->String(context);
55 if (rhs == NULL)
56 return this;
57 }
58
59 return lhs->Concat(context, rhs);
60 }
61
62 if (CYNumber *lhn = lhs_->Number(context))
63 if (CYNumber *rhn = rhs_->Number(context))
64 return $D(lhn->Value() + rhn->Value());
65
66 return this;
67 }
68
69 CYExpression *CYAddressOf::Replace(CYContext &context) {
70 return $C0($M(rhs_, $S("$cya")));
71 }
72
73 CYArgument *CYArgument::Replace(CYContext &context) { $T(NULL)
74 context.Replace(value_);
75 next_ = next_->Replace(context);
76
77 if (value_ == NULL) {
78 if (next_ == NULL)
79 return NULL;
80 else
81 value_ = $U;
82 }
83
84 return this;
85 }
86
87 CYExpression *CYArray::Replace(CYContext &context) {
88 if (elements_ != NULL)
89 elements_->Replace(context);
90 return this;
91 }
92
93 CYExpression *CYArrayComprehension::Replace(CYContext &context) {
94 CYVariable *cyv($V("$cyv"));
95
96 return $C0($F(NULL, $P1($L($I("$cyv")), comprehensions_->Parameters(context)), $$->*
97 $E($ CYAssign(cyv, $ CYArray()))->*
98 comprehensions_->Replace(context, $E($C1($M(cyv, $S("push")), expression_)))->*
99 $ CYReturn(cyv)
100 ));
101 }
102
103 CYExpression *CYAssignment::Replace(CYContext &context) {
104 context.Replace(lhs_);
105 context.Replace(rhs_);
106 return this;
107 }
108
109 CYStatement *CYBlock::Return() {
110 CYImplicitReturn(code_);
111 return this;
112 }
113
114 CYStatement *CYBlock::Replace(CYContext &context) {
115 context.ReplaceAll(code_);
116 if (code_ == NULL)
117 return $ CYEmpty();
118 return this;
119 }
120
121 CYStatement *CYBreak::Replace(CYContext &context) {
122 return this;
123 }
124
125 CYExpression *CYCall::AddArgument(CYContext &context, CYExpression *value) {
126 CYArgument **argument(&arguments_);
127 while (*argument != NULL)
128 argument = &(*argument)->next_;
129 *argument = $ CYArgument(value);
130 return this;
131 }
132
133 CYExpression *CYCall::Replace(CYContext &context) {
134 context.Replace(function_);
135 arguments_->Replace(context);
136 return this;
137 }
138
139 namespace cy {
140 namespace Syntax {
141
142 void Catch::Replace(CYContext &context) { $T()
143 CYScope scope(true, context);
144
145 context.Replace(name_);
146 context.scope_->Declare(context, name_, CYIdentifierCatch);
147
148 context.ReplaceAll(code_);
149 scope.Close(context, code_);
150 }
151
152 } }
153
154 CYExpression *CYClassExpression::Replace(CYContext &context) {
155 CYBuilder builder;
156
157 CYIdentifier *super(context.Unique());
158
159 CYIdentifier *old(context.super_);
160 context.super_ = super;
161
162 CYIdentifier *constructor(context.Unique());
163 CYForEach (member, tail_->static_)
164 member->Replace(context, builder, $V(constructor), true);
165
166 CYIdentifier *prototype(context.Unique());
167 CYForEach (member, tail_->instance_)
168 member->Replace(context, builder, $V(prototype), true);
169
170 if (tail_->constructor_ == NULL)
171 tail_->constructor_ = $ CYFunctionExpression(NULL, NULL, NULL);
172 tail_->constructor_ = CYSuperize(context, tail_->constructor_);
173
174 context.super_ = old;
175
176 return $C1($ CYFunctionExpression(NULL, $P($L(super)), $$
177 ->* $ CYVar($L1($L(constructor, tail_->constructor_)))
178 ->* $ CYVar($L1($L(prototype, $ CYFunctionExpression(NULL, NULL, NULL))))
179 ->* $E($ CYAssign($M($V(prototype), $S("prototype")), $M($V(super), $S("prototype"))))
180 ->* $E($ CYAssign($V(prototype), $N($V(prototype))))
181 ->* $E($ CYAssign($M($V(prototype), $S("constructor")), $V(constructor)))
182 ->* $ CYVar(builder.declarations_)
183 ->* builder.statements_
184 ->* $E($ CYAssign($M($V(constructor), $S("prototype")), $V(prototype)))
185 ->* $ CYReturn($V(constructor))
186 ), tail_->extends_ ?: $V($I("Object")));
187 }
188
189 CYStatement *CYClassStatement::Replace(CYContext &context) {
190 return $ CYVar($L1($L(name_, $ CYClassExpression(name_, tail_))));
191 }
192
193 void CYClause::Replace(CYContext &context) { $T()
194 context.Replace(case_);
195 context.ReplaceAll(code_);
196 next_->Replace(context);
197 }
198
199 CYExpression *CYCompound::Replace(CYContext &context) {
200 context.Replace(expression_);
201 context.Replace(next_);
202
203 if (CYCompound *compound = dynamic_cast<CYCompound *>(expression_)) {
204 expression_ = compound->expression_;
205 compound->expression_ = compound->next_;
206 compound->next_ = next_;
207 next_ = compound;
208 }
209
210 return this;
211 }
212
213 CYFunctionParameter *CYCompound::Parameter() const {
214 CYFunctionParameter *next(next_->Parameter());
215 if (next == NULL)
216 return NULL;
217
218 CYFunctionParameter *parameter(expression_->Parameter());
219 if (parameter == NULL)
220 return NULL;
221
222 parameter->SetNext(next);
223 return parameter;
224 }
225
226 CYFunctionParameter *CYComprehension::Parameters(CYContext &context) const { $T(NULL)
227 CYFunctionParameter *next(next_->Parameters(context));
228 if (CYFunctionParameter *parameter = Parameter(context)) {
229 parameter->SetNext(next);
230 return parameter;
231 } else
232 return next;
233 }
234
235 CYStatement *CYComprehension::Replace(CYContext &context, CYStatement *statement) const {
236 return next_ == NULL ? statement : next_->Replace(context, statement);
237 }
238
239 CYExpression *CYComputed::PropertyName(CYContext &context) {
240 return expression_;
241 }
242
243 CYExpression *CYCondition::Replace(CYContext &context) {
244 context.Replace(test_);
245 context.Replace(true_);
246 context.Replace(false_);
247 return this;
248 }
249
250 void CYContext::NonLocal(CYStatement *&statements) {
251 CYContext &context(*this);
252
253 if (nextlocal_ != NULL && nextlocal_->identifier_ != NULL) {
254 CYIdentifier *cye($I("$cye")->Replace(context));
255 CYIdentifier *unique(nextlocal_->identifier_->Replace(context));
256
257 CYStatement *declare(
258 $ CYVar($L1($L(unique, $ CYObject()))));
259
260 cy::Syntax::Catch *rescue(
261 $ cy::Syntax::Catch(cye, $$->*
262 $ CYIf($ CYIdentical($M($V(cye), $S("$cyk")), $V(unique)), $$->*
263 $ CYReturn($M($V(cye), $S("$cyv"))))->*
264 $ cy::Syntax::Throw($V(cye))));
265
266 // XXX: I don't understand any of this
267 context.Replace(declare);
268 rescue->Replace(context);
269
270 statements = $$->*
271 declare->*
272 $ cy::Syntax::Try(statements, rescue, NULL);
273 }
274 }
275
276 CYIdentifier *CYContext::Unique() {
277 return $ CYIdentifier($pool.strcat("$cy", $pool.itoa(unique_++), NULL));
278 }
279
280 CYStatement *CYContinue::Replace(CYContext &context) {
281 return this;
282 }
283
284 CYStatement *CYDebugger::Replace(CYContext &context) {
285 return this;
286 }
287
288 CYAssignment *CYDeclaration::Assignment(CYContext &context) {
289 if (initialiser_ == NULL)
290 return NULL;
291
292 CYAssignment *value($ CYAssign(Variable(context), initialiser_));
293 initialiser_ = NULL;
294 return value;
295 }
296
297 CYVariable *CYDeclaration::Variable(CYContext &context) {
298 return $V(identifier_);
299 }
300
301 CYStatement *CYDeclaration::ForEachIn(CYContext &context, CYExpression *value) {
302 return $ CYVar($L1($ CYDeclaration(identifier_, value)));
303 }
304
305 CYExpression *CYDeclaration::Replace(CYContext &context) {
306 context.Replace(identifier_);
307 context.scope_->Declare(context, identifier_, CYIdentifierVariable);
308 return Variable(context);
309 }
310
311 void CYDeclarations::Replace(CYContext &context) { $T()
312 declaration_->Replace(context);
313 next_->Replace(context);
314 }
315
316 CYFunctionParameter *CYDeclarations::Parameter(CYContext &context) { $T(NULL)
317 return $ CYFunctionParameter($ CYDeclaration(declaration_->identifier_), next_->Parameter(context));
318 }
319
320 CYArgument *CYDeclarations::Argument(CYContext &context) { $T(NULL)
321 return $ CYArgument(declaration_->initialiser_, next_->Argument(context));
322 }
323
324 CYExpression *CYDeclarations::Expression(CYContext &context) { $T(NULL)
325 CYExpression *compound(next_->Expression(context));
326 if (CYAssignment *assignment = declaration_->Assignment(context))
327 if (compound == NULL)
328 compound = assignment;
329 else
330 compound = $ CYCompound(assignment, compound);
331 return compound;
332 }
333
334 CYExpression *CYDirectMember::Replace(CYContext &context) {
335 context.Replace(object_);
336 context.Replace(property_);
337 return this;
338 }
339
340 CYStatement *CYDoWhile::Replace(CYContext &context) {
341 context.Replace(test_);
342 context.ReplaceAll(code_);
343 return this;
344 }
345
346 void CYElementSpread::Replace(CYContext &context) {
347 context.Replace(value_);
348 }
349
350 void CYElementValue::Replace(CYContext &context) {
351 context.Replace(value_);
352 if (next_ != NULL)
353 next_->Replace(context);
354 }
355
356 CYStatement *CYEmpty::Replace(CYContext &context) {
357 return NULL;
358 }
359
360 CYExpression *CYEncodedType::Replace(CYContext &context) {
361 return typed_->Replace(context);
362 }
363
364 CYStatement *CYExpress::Return() {
365 return $ CYReturn(expression_);
366 }
367
368 CYStatement *CYExpress::Replace(CYContext &context) {
369 context.Replace(expression_);
370 return this;
371 }
372
373 CYExpression *CYExpression::AddArgument(CYContext &context, CYExpression *value) {
374 return $C1(this, value);
375 }
376
377 CYStatement *CYExpression::ForEachIn(CYContext &context, CYExpression *value) {
378 return $E($ CYAssign(this, value));
379 }
380
381 CYAssignment *CYExpression::Assignment(CYContext &context) {
382 return NULL;
383 }
384
385 CYFunctionParameter *CYExpression::Parameter() const {
386 return NULL;
387 }
388
389 CYStatement *CYExternal::Replace(CYContext &context) {
390 return $E($ CYAssign($V(typed_->identifier_), $C1(typed_->Replace(context), $C2($V("dlsym"), $V("RTLD_DEFAULT"), $S(typed_->identifier_->Word())))));
391 }
392
393 CYNumber *CYFalse::Number(CYContext &context) {
394 return $D(0);
395 }
396
397 CYString *CYFalse::String(CYContext &context) {
398 return $S("false");
399 }
400
401 CYExpression *CYFatArrow::Replace(CYContext &context) {
402 CYFunctionExpression *function($ CYFunctionExpression(NULL, parameters_, code_));
403 function->this_.SetNext(context.this_);
404 return function;
405 }
406
407 void CYFinally::Replace(CYContext &context) { $T()
408 context.ReplaceAll(code_);
409 }
410
411 CYStatement *CYFor::Replace(CYContext &context) {
412 context.Replace(initialiser_);
413 context.Replace(test_);
414 context.Replace(increment_);
415 context.ReplaceAll(code_);
416 return this;
417 }
418
419 CYExpression *CYForDeclarations::Replace(CYContext &context) {
420 declarations_->Replace(context);
421 return declarations_->Expression(context);
422 }
423
424 // XXX: this still feels highly suboptimal
425 CYStatement *CYForIn::Replace(CYContext &context) {
426 if (CYAssignment *assignment = initialiser_->Assignment(context))
427 return $ CYBlock($$->*
428 $E(assignment)->*
429 this
430 );
431
432 context.Replace(initialiser_);
433 context.Replace(set_);
434 context.ReplaceAll(code_);
435 return this;
436 }
437
438 CYFunctionParameter *CYForInComprehension::Parameter(CYContext &context) const {
439 return $ CYFunctionParameter(declaration_);
440 }
441
442 CYStatement *CYForInComprehension::Replace(CYContext &context, CYStatement *statement) const {
443 return $ CYForIn(declaration_->Variable(context), set_, CYComprehension::Replace(context, statement));
444 }
445
446 CYStatement *CYForOf::Replace(CYContext &context) {
447 if (CYAssignment *assignment = initialiser_->Assignment(context))
448 return $ CYBlock($$->*
449 $E(assignment)->*
450 this
451 );
452
453 CYIdentifier *cys($I("$cys")), *cyt($I("$cyt"));
454
455 return $ CYLetStatement($L2($ CYDeclaration(cys, set_), $ CYDeclaration(cyt)), $$->*
456 $ CYForIn($V(cyt), $V(cys), $ CYBlock($$->*
457 initialiser_->ForEachIn(context, $M($V(cys), $V(cyt)))->*
458 code_
459 ))
460 );
461 }
462
463 CYFunctionParameter *CYForOfComprehension::Parameter(CYContext &context) const {
464 return $ CYFunctionParameter(declaration_);
465 }
466
467 CYStatement *CYForOfComprehension::Replace(CYContext &context, CYStatement *statement) const {
468 CYIdentifier *cys($I("$cys"));
469
470 return $E($C0($F(NULL, $P1($L($I("$cys"))), $$->*
471 $E($ CYAssign($V(cys), set_))->*
472 $ CYForIn(declaration_->Variable(context), $V(cys), $ CYBlock($$->*
473 $E($ CYAssign(declaration_->Variable(context), $M($V(cys), declaration_->Variable(context))))->*
474 CYComprehension::Replace(context, statement)
475 ))
476 )));
477 }
478
479 void CYFunction::Replace(CYContext &context) {
480 CYThisScope *_this(context.this_);
481 context.this_ = &this_;
482 context.this_ = CYGetLast(context.this_);
483
484 CYIdentifier *super(context.super_);
485 context.super_ = super_;
486
487 CYNonLocal *nonlocal(context.nonlocal_);
488 CYNonLocal *nextlocal(context.nextlocal_);
489
490 bool localize;
491 if (nonlocal_ != NULL) {
492 localize = false;
493 context.nonlocal_ = nonlocal_;
494 } else {
495 localize = true;
496 nonlocal_ = $ CYNonLocal();
497 context.nextlocal_ = nonlocal_;
498 }
499
500 CYScope scope(!localize, context);
501
502 parameters_->Replace(context, code_);
503
504 context.ReplaceAll(code_);
505
506 if (implicit_)
507 CYImplicitReturn(code_);
508
509 if (CYIdentifier *identifier = this_.identifier_) {
510 context.scope_->Declare(context, identifier, CYIdentifierVariable);
511 code_ = $$
512 ->*$E($ CYAssign($V(identifier), $ CYThis()))
513 ->*code_
514 ;
515 }
516
517 if (localize)
518 context.NonLocal(code_);
519
520 context.nextlocal_ = nextlocal;
521 context.nonlocal_ = nonlocal;
522
523 context.super_ = super;
524 context.this_ = _this;
525
526 scope.Close(context, code_);
527 }
528
529 CYExpression *CYFunctionExpression::Replace(CYContext &context) {
530 CYScope scope(false, context);
531 if (name_ != NULL)
532 context.scope_->Declare(context, name_, CYIdentifierOther);
533 CYFunction::Replace(context);
534 scope.Close(context, code_);
535 return this;
536 }
537
538 void CYFunctionParameter::Replace(CYContext &context, CYStatement *&statements) { $T()
539 CYAssignment *assignment(initialiser_->Assignment(context));
540 context.Replace(initialiser_);
541
542 next_->Replace(context, statements);
543
544 if (assignment != NULL)
545 statements = $$->*
546 // XXX: this cast is quite incorrect
547 $ CYIf($ CYIdentical($ CYTypeOf(dynamic_cast<CYExpression *>(initialiser_)), $S("undefined")), $$->*
548 $E(assignment)
549 )->*
550 statements;
551 }
552
553 CYStatement *CYFunctionStatement::Replace(CYContext &context) {
554 context.scope_->Declare(context, name_, CYIdentifierOther);
555 CYFunction::Replace(context);
556 return this;
557 }
558
559 CYIdentifier *CYIdentifier::Replace(CYContext &context) {
560 if (replace_ != NULL && replace_ != this)
561 return replace_->Replace(context);
562 replace_ = context.scope_->Lookup(context, this);
563 return replace_;
564 }
565
566 CYStatement *CYIf::Return() {
567 CYImplicitReturn(true_);
568 CYImplicitReturn(false_);
569 return this;
570 }
571
572 CYStatement *CYIf::Replace(CYContext &context) {
573 context.Replace(test_);
574 context.ReplaceAll(true_);
575 context.ReplaceAll(false_);
576 return this;
577 }
578
579 CYFunctionParameter *CYIfComprehension::Parameter(CYContext &context) const {
580 return NULL;
581 }
582
583 CYStatement *CYIfComprehension::Replace(CYContext &context, CYStatement *statement) const {
584 return $ CYIf(test_, CYComprehension::Replace(context, statement));
585 }
586
587 CYStatement *CYImport::Replace(CYContext &context) {
588 return $ CYVar($L1($L($I(module_->part_->Word()), $C1($V("require"), module_->Replace(context, "/")))));
589 }
590
591 CYExpression *CYIndirect::Replace(CYContext &context) {
592 return $M(rhs_, $S("$cyi"));
593 }
594
595 CYExpression *CYIndirectMember::Replace(CYContext &context) {
596 return $M($ CYIndirect(object_), property_);
597 }
598
599 CYExpression *CYInfix::Replace(CYContext &context) {
600 context.Replace(lhs_);
601 context.Replace(rhs_);
602 return this;
603 }
604
605 CYStatement *CYLabel::Replace(CYContext &context) {
606 context.Replace(statement_);
607 return this;
608 }
609
610 CYExpression *CYLambda::Replace(CYContext &context) {
611 return $N2($V("Functor"), $ CYFunctionExpression(NULL, parameters_->Parameters(context), code_), parameters_->TypeSignature(context, typed_->Replace(context)));
612 }
613
614 CYStatement *CYLetStatement::Replace(CYContext &context) {
615 return $E($ CYCall(CYNonLocalize(context, $ CYFunctionExpression(NULL, declarations_->Parameter(context), code_)), declarations_->Argument(context)));
616 }
617
618 CYFunctionExpression *CYMethod::Constructor() {
619 return NULL;
620 }
621
622 void CYMethod::Replace(CYContext &context) {
623 CYFunction::Replace(context);
624 }
625
626 CYString *CYModule::Replace(CYContext &context, const char *separator) const {
627 if (next_ == NULL)
628 return $ CYString(part_);
629 return $ CYString($pool.strcat(next_->Replace(context, separator)->Value(), separator, part_->Word(), NULL));
630 }
631
632 CYExpression *CYMultiply::Replace(CYContext &context) {
633 CYInfix::Replace(context);
634
635 if (CYNumber *lhn = lhs_->Number(context))
636 if (CYNumber *rhn = rhs_->Number(context))
637 return $D(lhn->Value() * rhn->Value());
638
639 return this;
640 }
641
642 namespace cy {
643 namespace Syntax {
644
645 CYExpression *New::AddArgument(CYContext &context, CYExpression *value) {
646 CYSetLast(arguments_) = $ CYArgument(value);
647 return this;
648 }
649
650 CYExpression *New::Replace(CYContext &context) {
651 context.Replace(constructor_);
652 arguments_->Replace(context);
653 return this;
654 }
655
656 } }
657
658 CYNumber *CYNull::Number(CYContext &context) {
659 return $D(0);
660 }
661
662 CYString *CYNull::String(CYContext &context) {
663 return $S("null");
664 }
665
666 CYNumber *CYNumber::Number(CYContext &context) {
667 return this;
668 }
669
670 CYString *CYNumber::String(CYContext &context) {
671 // XXX: there is a precise algorithm for this
672 return $S($pool.sprintf(24, "%.17g", Value()));
673 }
674
675 CYExpression *CYNumber::PropertyName(CYContext &context) {
676 return String(context);
677 }
678
679 CYExpression *CYObject::Replace(CYContext &context) {
680 CYBuilder builder;
681 if (properties_ != NULL)
682 properties_ = properties_->ReplaceAll(context, builder, $ CYThis(), false);
683
684 if (builder) {
685 return $C1($M($ CYFunctionExpression(NULL, builder.declarations_->Parameter(context),
686 builder.statements_->*
687 $ CYReturn($ CYThis())
688 ), $S("call")), this, builder.declarations_->Argument(context));
689 }
690
691 CYForEach (property, properties_)
692 property->Replace(context);
693 return this;
694 }
695
696 CYExpression *CYParenthetical::Replace(CYContext &context) {
697 return expression_;
698 }
699
700 CYExpression *CYPostfix::Replace(CYContext &context) {
701 context.Replace(lhs_);
702 return this;
703 }
704
705 CYExpression *CYPrefix::Replace(CYContext &context) {
706 context.Replace(rhs_);
707 return this;
708 }
709
710 CYProperty *CYProperty::ReplaceAll(CYContext &context, CYBuilder &builder, CYExpression *self, bool update) {
711 update |= name_->Computed();
712 if (update)
713 Replace(context, builder, self, true);
714 if (next_ != NULL)
715 next_ = next_->ReplaceAll(context, builder, self, update);
716 return update ? next_ : this;
717 }
718
719 void CYProperty::Replace(CYContext &context, CYBuilder &builder, CYExpression *self, bool computed) {
720 CYExpression *name(name_->PropertyName(context));
721 if (computed) {
722 CYIdentifier *unique(context.Unique());
723 builder.declarations_->*$L1($L(unique, name));
724 name = $V(unique);
725 }
726
727 Replace(context, builder, self, name);
728 }
729
730 void CYPropertyGetter::Replace(CYContext &context, CYBuilder &builder, CYExpression *self, CYExpression *name) {
731 CYIdentifier *unique(context.Unique());
732 builder.declarations_
733 ->* $L1($L(unique, CYSuperize(context, $ CYFunctionExpression(NULL, parameters_, code_))));
734 builder.statements_
735 ->* $E($C3($M($V("Object"), $S("defineProperty")), self, name, $ CYObject(CYList<CYProperty>()
736 ->* $ CYPropertyValue($S("configurable"), $ CYTrue())
737 ->* $ CYPropertyValue($S("enumerable"), $ CYTrue())
738 ->* $ CYPropertyValue($S("get"), $V(unique))
739 )));
740 }
741
742 CYFunctionExpression *CYPropertyMethod::Constructor() {
743 return name_->Constructor() ? $ CYFunctionExpression(NULL, parameters_, code_) : NULL;
744 }
745
746 void CYPropertyMethod::Replace(CYContext &context, CYBuilder &builder, CYExpression *self, CYExpression *name) {
747 CYIdentifier *unique(context.Unique());
748 builder.declarations_
749 ->* $L1($L(unique, CYSuperize(context, $ CYFunctionExpression(NULL, parameters_, code_))));
750 builder.statements_
751 ->* $E($ CYAssign($M(self, name), $V(unique)));
752 }
753
754 void CYPropertySetter::Replace(CYContext &context, CYBuilder &builder, CYExpression *self, CYExpression *name) {
755 CYIdentifier *unique(context.Unique());
756 builder.declarations_
757 ->* $L1($L(unique, CYSuperize(context, $ CYFunctionExpression(NULL, parameters_, code_))));
758 builder.statements_
759 ->* $E($C3($M($V("Object"), $S("defineProperty")), self, name, $ CYObject(CYList<CYProperty>()
760 ->* $ CYPropertyValue($S("configurable"), $ CYTrue())
761 ->* $ CYPropertyValue($S("enumerable"), $ CYTrue())
762 ->* $ CYPropertyValue($S("set"), $V(unique))
763 )));
764 }
765
766 void CYPropertyValue::Replace(CYContext &context, CYBuilder &builder, CYExpression *self, CYExpression *name) {
767 CYIdentifier *unique(context.Unique());
768 builder.declarations_
769 ->* $L1($L(unique, value_));
770 builder.statements_
771 ->* $E($ CYAssign($M(self, name), $V(unique)));
772 }
773
774 void CYPropertyValue::Replace(CYContext &context) {
775 context.Replace(value_);
776 }
777
778 // XXX: this is evil evil black magic. don't ask, don't tell... don't believe!
779 #define MappingSet "0etnirsoalfucdphmgyvbxTwSNECAFjDLkMOIBPqzRH$_WXUVGYKQJZ"
780 //#define MappingSet "0abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_"
781
782 namespace {
783 struct IdentifierUsageLess :
784 std::binary_function<CYIdentifier *, CYIdentifier *, bool>
785 {
786 _finline bool operator ()(CYIdentifier *lhs, CYIdentifier *rhs) const {
787 if (lhs->usage_ != rhs->usage_)
788 return lhs->usage_ > rhs->usage_;
789 return lhs < rhs;
790 }
791 };
792
793 typedef std::set<CYIdentifier *, IdentifierUsageLess> IdentifierUsages;
794 }
795
796 void CYScript::Replace(CYContext &context) {
797 CYScope scope(true, context);
798
799 context.nextlocal_ = $ CYNonLocal();
800 context.ReplaceAll(code_);
801 context.NonLocal(code_);
802
803 scope.Close(context, code_);
804
805 size_t offset(0);
806
807 CYCStringSet external;
808 for (CYIdentifierValueSet::const_iterator i(scope.identifiers_.begin()); i != scope.identifiers_.end(); ++i)
809 external.insert((*i)->Word());
810
811 IdentifierUsages usages;
812
813 if (offset < context.rename_.size())
814 CYForEach (i, context.rename_[offset].identifier_)
815 usages.insert(i);
816
817 // XXX: totalling the probable occurrences and sorting by them would improve the result
818 for (CYIdentifierUsageVector::const_iterator i(context.rename_.begin()); i != context.rename_.end(); ++i, ++offset) {
819 //std::cout << *i << ":" << (*i)->offset_ << std::endl;
820
821 const char *name;
822
823 if (context.options_.verbose_)
824 name = $pool.strcat("$", $pool.itoa(offset), NULL);
825 else {
826 char id[8];
827 id[7] = '\0';
828
829 id:
830 unsigned position(7), local(offset + 1);
831
832 do {
833 unsigned index(local % (sizeof(MappingSet) - 1));
834 local /= sizeof(MappingSet) - 1;
835 id[--position] = MappingSet[index];
836 } while (local != 0);
837
838 if (external.find(id + position) != external.end()) {
839 ++offset;
840 goto id;
841 }
842
843 name = $pool.strmemdup(id + position, 7 - position);
844 // XXX: at some point, this could become a keyword
845 }
846
847 CYForEach (identifier, i->identifier_)
848 identifier->Set(name);
849 }
850 }
851
852 CYStatement *CYReturn::Replace(CYContext &context) {
853 if (context.nonlocal_ != NULL) {
854 CYProperty *value(value_ == NULL ? NULL : $ CYPropertyValue($S("$cyv"), value_));
855 return $ cy::Syntax::Throw($ CYObject(
856 $ CYPropertyValue($S("$cyk"), $V(context.nonlocal_->Target(context)), value)
857 ));
858 }
859
860 context.Replace(value_);
861 return this;
862 }
863
864 CYExpression *CYRubyBlock::Replace(CYContext &context) {
865 return call_->AddArgument(context, proc_->Replace(context));
866 }
867
868 CYExpression *CYRubyBlock::AddArgument(CYContext &context, CYExpression *value) {
869 return Replace(context)->AddArgument(context, value);
870 }
871
872 CYExpression *CYRubyProc::Replace(CYContext &context) {
873 CYFunctionExpression *function($ CYFunctionExpression(NULL, parameters_, code_));
874 function = CYNonLocalize(context, function);
875 function->implicit_ = true;
876 return function;
877 }
878
879 CYScope::CYScope(bool transparent, CYContext &context) :
880 transparent_(transparent),
881 parent_(context.scope_)
882 {
883 context.scope_ = this;
884 }
885
886 void CYScope::Declare(CYContext &context, CYIdentifier *identifier, CYIdentifierFlags flags) {
887 if (!transparent_ || flags == CYIdentifierArgument || flags == CYIdentifierCatch)
888 internal_.insert(CYIdentifierAddressFlagsMap::value_type(identifier, flags));
889 else if (parent_ != NULL)
890 parent_->Declare(context, identifier, flags);
891 }
892
893 CYIdentifier *CYScope::Lookup(CYContext &context, CYIdentifier *identifier) {
894 std::pair<CYIdentifierValueSet::iterator, bool> insert(identifiers_.insert(identifier));
895 return *insert.first;
896 }
897
898 void CYScope::Merge(CYContext &context, CYIdentifier *identifier) {
899 std::pair<CYIdentifierValueSet::iterator, bool> insert(identifiers_.insert(identifier));
900 if (!insert.second) {
901 if ((*insert.first)->offset_ < identifier->offset_)
902 (*insert.first)->offset_ = identifier->offset_;
903 identifier->replace_ = *insert.first;
904 (*insert.first)->usage_ += identifier->usage_ + 1;
905 }
906 }
907
908 namespace {
909 struct IdentifierOffset {
910 size_t offset_;
911 CYIdentifierFlags flags_;
912 size_t usage_;
913 CYIdentifier *identifier_;
914
915 IdentifierOffset(CYIdentifier *identifier, CYIdentifierFlags flags) :
916 offset_(identifier->offset_),
917 flags_(flags),
918 usage_(identifier->usage_),
919 identifier_(identifier)
920 {
921 }
922 };
923
924 struct IdentifierOffsetLess :
925 std::binary_function<const IdentifierOffset &, const IdentifierOffset &, bool>
926 {
927 _finline bool operator ()(const IdentifierOffset &lhs, const IdentifierOffset &rhs) const {
928 if (lhs.offset_ != rhs.offset_)
929 return lhs.offset_ < rhs.offset_;
930 if (lhs.flags_ != rhs.flags_)
931 return lhs.flags_ < rhs.flags_;
932 /*if (lhs.usage_ != rhs.usage_)
933 return lhs.usage_ < rhs.usage_;*/
934 return lhs.identifier_ < rhs.identifier_;
935 }
936 };
937
938 typedef std::set<IdentifierOffset, IdentifierOffsetLess> IdentifierOffsets;
939 }
940
941 void CYScope::Close(CYContext &context, CYStatement *&statements) {
942 context.scope_ = parent_;
943
944 if (parent_ == NULL)
945 return;
946
947 CYDeclarations *last(NULL), *curr(NULL);
948
949 IdentifierOffsets offsets;
950
951 for (CYIdentifierAddressFlagsMap::const_iterator i(internal_.begin()); i != internal_.end(); ++i)
952 if (i->second != CYIdentifierMagic)
953 offsets.insert(IdentifierOffset(i->first, i->second));
954
955 size_t offset(0);
956
957 for (IdentifierOffsets::const_iterator i(offsets.begin()); i != offsets.end(); ++i) {
958 if (i->flags_ == CYIdentifierVariable) {
959 CYDeclarations *next($ CYDeclarations($ CYDeclaration(i->identifier_)));
960 if (last == NULL)
961 last = next;
962 if (curr != NULL)
963 curr->SetNext(next);
964 curr = next;
965 }
966
967 if (offset < i->offset_)
968 offset = i->offset_;
969 if (context.rename_.size() <= offset)
970 context.rename_.resize(offset + 1);
971
972 CYIdentifierUsage &rename(context.rename_[offset++]);
973 i->identifier_->SetNext(rename.identifier_);
974 rename.identifier_ = i->identifier_;
975 rename.usage_ += i->identifier_->usage_ + 1;
976 }
977
978 if (last != NULL) {
979 CYVar *var($ CYVar(last));
980 var->SetNext(statements);
981 statements = var;
982 }
983
984 for (CYIdentifierValueSet::const_iterator i(identifiers_.begin()); i != identifiers_.end(); ++i)
985 if (internal_.find(*i) == internal_.end()) {
986 //std::cout << *i << '=' << offset << std::endl;
987 if ((*i)->offset_ < offset)
988 (*i)->offset_ = offset;
989 parent_->Merge(context, *i);
990 }
991 }
992
993 CYElementValue *CYSpan::Replace(CYContext &context) { $T(NULL)
994 return $ CYElementValue(expression_, $ CYElementValue(string_, next_->Replace(context)));
995 }
996
997 CYStatement *CYStatement::Return() {
998 return this;
999 }
1000
1001 CYString *CYString::Concat(CYContext &context, CYString *rhs) const {
1002 size_t size(size_ + rhs->size_);
1003 char *value($ char[size + 1]);
1004 memcpy(value, value_, size_);
1005 memcpy(value + size_, rhs->value_, rhs->size_);
1006 value[size] = '\0';
1007 return $S(value, size);
1008 }
1009
1010 CYNumber *CYString::Number(CYContext &context) {
1011 // XXX: there is a precise algorithm for this
1012 return NULL;
1013 }
1014
1015 CYExpression *CYString::PropertyName(CYContext &context) {
1016 return this;
1017 }
1018
1019 CYString *CYString::String(CYContext &context) {
1020 return this;
1021 }
1022
1023 CYExpression *CYSuperAccess::Replace(CYContext &context) {
1024 return $C1($M($M($M($V(context.super_), $S("prototype")), property_), $S("bind")), $ CYThis());
1025 }
1026
1027 CYExpression *CYSuperCall::Replace(CYContext &context) {
1028 return $C($C1($M($V(context.super_), $S("bind")), $ CYThis()), arguments_);
1029 }
1030
1031 CYStatement *CYSwitch::Replace(CYContext &context) {
1032 context.Replace(value_);
1033 clauses_->Replace(context);
1034 return this;
1035 }
1036
1037 CYExpression *CYTemplate::Replace(CYContext &context) {
1038 return $C2($M($M($M($V("String"), $S("prototype")), $S("concat")), $S("apply")), $S(""), $ CYArray($ CYElementValue(string_, spans_->Replace(context))));
1039 }
1040
1041 CYExpression *CYThis::Replace(CYContext &context) {
1042 if (context.this_ != NULL)
1043 return $V(context.this_->Identifier(context));
1044 return this;
1045 }
1046
1047 namespace cy {
1048 namespace Syntax {
1049
1050 CYStatement *Throw::Replace(CYContext &context) {
1051 context.Replace(value_);
1052 return this;
1053 }
1054
1055 } }
1056
1057 CYExpression *CYTrivial::Replace(CYContext &context) {
1058 return this;
1059 }
1060
1061 CYNumber *CYTrue::Number(CYContext &context) {
1062 return $D(1);
1063 }
1064
1065 CYString *CYTrue::String(CYContext &context) {
1066 return $S("true");
1067 }
1068
1069 namespace cy {
1070 namespace Syntax {
1071
1072 CYStatement *Try::Replace(CYContext &context) {
1073 context.ReplaceAll(code_);
1074 catch_->Replace(context);
1075 finally_->Replace(context);
1076 return this;
1077 }
1078
1079 } }
1080
1081 CYExpression *CYTypeArrayOf::Replace_(CYContext &context, CYExpression *type) {
1082 return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("arrayOf")), $ CYArgument(size_)));
1083 }
1084
1085 CYExpression *CYTypeBlockWith::Replace_(CYContext &context, CYExpression *type) {
1086 return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("blockWith")), parameters_->Argument(context)));
1087 }
1088
1089 CYExpression *CYTypeConstant::Replace_(CYContext &context, CYExpression *type) {
1090 return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("constant"))));
1091 }
1092
1093 CYStatement *CYTypeDefinition::Replace(CYContext &context) {
1094 return $E($ CYAssign($V(typed_->identifier_), typed_->Replace(context)));
1095 }
1096
1097 CYExpression *CYTypeError::Replace(CYContext &context) {
1098 _assert(false);
1099 return NULL;
1100 }
1101
1102 CYExpression *CYTypeModifier::Replace(CYContext &context, CYExpression *type) { $T(type)
1103 return Replace_(context, type);
1104 }
1105
1106 CYExpression *CYTypeFunctionWith::Replace_(CYContext &context, CYExpression *type) {
1107 return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("functionWith")), parameters_->Argument(context)));
1108 }
1109
1110 CYExpression *CYTypeLong::Replace(CYContext &context) {
1111 return $ CYCall($ CYDirectMember(specifier_->Replace(context), $ CYString("long")));
1112 }
1113
1114 CYExpression *CYTypePointerTo::Replace_(CYContext &context, CYExpression *type) {
1115 return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("pointerTo"))));
1116 }
1117
1118 CYExpression *CYTypeShort::Replace(CYContext &context) {
1119 return $ CYCall($ CYDirectMember(specifier_->Replace(context), $ CYString("short")));
1120 }
1121
1122 CYExpression *CYTypeSigned::Replace(CYContext &context) {
1123 return $ CYCall($ CYDirectMember(specifier_->Replace(context), $ CYString("signed")));
1124 }
1125
1126 CYExpression *CYTypeUnsigned::Replace(CYContext &context) {
1127 return $ CYCall($ CYDirectMember(specifier_->Replace(context), $ CYString("unsigned")));
1128 }
1129
1130 CYExpression *CYTypeVariable::Replace(CYContext &context) {
1131 return $V(name_);
1132 }
1133
1134 CYExpression *CYTypeVoid::Replace(CYContext &context) {
1135 return $N1($V("Type"), $ CYString("v"));
1136 }
1137
1138 CYExpression *CYTypeVolatile::Replace_(CYContext &context, CYExpression *type) {
1139 return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("volatile"))));
1140 }
1141
1142 CYExpression *CYTypedIdentifier::Replace(CYContext &context) {
1143 return modifier_->Replace(context, specifier_->Replace(context));
1144 }
1145
1146 CYTypeFunctionWith *CYTypedIdentifier::Function() {
1147 CYTypeModifier **modifier(&modifier_);
1148 if (*modifier == NULL)
1149 return NULL;
1150 while ((*modifier)->next_ != NULL)
1151 modifier = &(*modifier)->next_;
1152 CYTypeFunctionWith *function((*modifier)->Function());
1153 if (function == NULL)
1154 return NULL;
1155 *modifier = NULL;
1156 return function;
1157 }
1158
1159 CYArgument *CYTypedParameter::Argument(CYContext &context) { $T(NULL)
1160 return $ CYArgument(typed_->Replace(context), next_->Argument(context));
1161 }
1162
1163 CYFunctionParameter *CYTypedParameter::Parameters(CYContext &context) { $T(NULL)
1164 return $ CYFunctionParameter($ CYDeclaration(typed_->identifier_ ?: context.Unique()), next_->Parameters(context));
1165 }
1166
1167 CYExpression *CYTypedParameter::TypeSignature(CYContext &context, CYExpression *prefix) { $T(prefix)
1168 return next_->TypeSignature(context, $ CYAdd(prefix, typed_->Replace(context)));
1169 }
1170
1171 CYStatement *CYVar::Replace(CYContext &context) {
1172 declarations_->Replace(context);
1173 if (CYExpression *expression = declarations_->Expression(context))
1174 return $E(expression);
1175 return $ CYEmpty();
1176 }
1177
1178 CYExpression *CYVariable::Replace(CYContext &context) {
1179 context.Replace(name_);
1180 return this;
1181 }
1182
1183 CYFunctionParameter *CYVariable::Parameter() const {
1184 return $ CYFunctionParameter($ CYDeclaration(name_));
1185 }
1186
1187 CYStatement *CYWhile::Replace(CYContext &context) {
1188 context.Replace(test_);
1189 context.ReplaceAll(code_);
1190 return this;
1191 }
1192
1193 CYStatement *CYWith::Replace(CYContext &context) {
1194 context.Replace(scope_);
1195 context.ReplaceAll(code_);
1196 return this;
1197 }
1198
1199 CYExpression *CYWord::PropertyName(CYContext &context) {
1200 return $S(this);
1201 }