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