]> git.saurik.com Git - cycript.git/blob - Output.cpp
Found the garbage collection bug from hell (classes apparently really need /something...
[cycript.git] / Output.cpp
1 /* Cycript - Remove Execution Server and Disassembler
2 * Copyright (C) 2009 Jay Freeman (saurik)
3 */
4
5 /* Modified BSD License {{{ */
6 /*
7 * Redistribution and use in source and binary
8 * forms, with or without modification, are permitted
9 * provided that the following conditions are met:
10 *
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
18 * distribution.
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.
22 *
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.
37 */
38 /* }}} */
39
40 #include "cycript.hpp"
41 #include "Parser.hpp"
42
43 #include <sstream>
44
45 _finline CYFlags operator ~(CYFlags rhs) {
46 return static_cast<CYFlags>(~static_cast<unsigned>(rhs));
47 }
48
49 _finline CYFlags operator &(CYFlags lhs, CYFlags rhs) {
50 return static_cast<CYFlags>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs));
51 }
52
53 _finline CYFlags operator |(CYFlags lhs, CYFlags rhs) {
54 return static_cast<CYFlags>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs));
55 }
56
57 _finline CYFlags &operator |=(CYFlags &lhs, CYFlags rhs) {
58 return lhs = lhs | rhs;
59 }
60
61 _finline CYFlags CYLeft(CYFlags flags) {
62 return flags & ~CYNoDangle;
63 }
64
65 _finline CYFlags CYRight(CYFlags flags) {
66 return flags & ~CYNoBF;
67 }
68
69 _finline CYFlags CYCenter(CYFlags flags) {
70 return CYLeft(CYRight(flags));
71 }
72
73 void CYOutput::Terminate() {
74 out_ << ';';
75 mode_ = NoMode;
76 }
77
78 CYOutput &CYOutput::operator <<(char rhs) {
79 if (rhs == ' ' || rhs == '\n')
80 if (pretty_)
81 out_ << rhs;
82 else goto done;
83 else if (rhs == '\t')
84 if (pretty_)
85 for (unsigned i(0); i != indent_; ++i)
86 out_ << " ";
87 else goto done;
88 else goto work;
89
90 mode_ = NoMode;
91 goto done;
92
93 work:
94 if (mode_ == Terminated && rhs != '}')
95 out_ << ';';
96
97 if (rhs == ';') {
98 if (pretty_)
99 goto none;
100 else {
101 mode_ = Terminated;
102 goto done;
103 }
104 } else if (rhs == '+') {
105 if (mode_ == NoPlus)
106 out_ << ' ';
107 mode_ = NoPlus;
108 } else if (rhs == '-') {
109 if (mode_ == NoHyphen)
110 out_ << ' ';
111 mode_ = NoHyphen;
112 } else if (WordEndRange_[rhs]) {
113 if (mode_ == NoLetter)
114 out_ << ' ';
115 mode_ = NoLetter;
116 } else none:
117 mode_ = NoMode;
118
119 out_ << rhs;
120 done:
121 return *this;
122 }
123
124 CYOutput &CYOutput::operator <<(const char *rhs) {
125 size_t size(strlen(rhs));
126
127 if (size == 1)
128 return *this << *rhs;
129
130 if (mode_ == Terminated)
131 out_ << ';';
132 else if (
133 mode_ == NoPlus && *rhs == '+' ||
134 mode_ == NoHyphen && *rhs == '-' ||
135 mode_ == NoLetter && WordEndRange_[*rhs]
136 )
137 out_ << ' ';
138
139 if (WordEndRange_[rhs[size - 1]])
140 mode_ = NoLetter;
141 else
142 mode_ = NoMode;
143
144 out_ << rhs;
145 return *this;
146 }
147
148 void CYArgument::Output(CYOutput &out) const {
149 if (name_ != NULL) {
150 out << *name_;
151 if (value_ != NULL)
152 out << ':' << ' ';
153 }
154 if (value_ != NULL)
155 value_->Output(out, CYPA, CYNoFlags);
156 if (next_ != NULL) {
157 if (next_->name_ == NULL)
158 out << ',';
159 out << ' ' << *next_;
160 }
161 }
162
163 void CYArray::Output(CYOutput &out, CYFlags flags) const {
164 out << '[' << elements_ << ']';
165 }
166
167 void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
168 out << '[' << *expression_ << ' ' << *comprehensions_ << ']';
169 }
170
171 void CYAssignment::Output(CYOutput &out, CYFlags flags) const {
172 lhs_->Output(out, Precedence() - 1, CYLeft(flags) | CYNoRightHand);
173 out << ' ' << Operator() << ' ';
174 rhs_->Output(out, Precedence(), CYRight(flags));
175 }
176
177 void CYBlock::Output(CYOutput &out) const {
178 out << '{' << '\n';
179 ++out.indent_;
180 if (statements_ != NULL)
181 statements_->Multiple(out);
182 --out.indent_;
183 out << '\t' << '}';
184 }
185
186 void CYBlock::Output(CYOutput &out, CYFlags flags) const {
187 if (statements_ == NULL)
188 out.Terminate();
189 else if (statements_->next_ == NULL)
190 statements_->Single(out, flags);
191 else
192 Output(out);
193 }
194
195 void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
196 out << (Value() ? "true" : "false");
197 }
198
199 void CYBreak::Output(CYOutput &out, CYFlags flags) const {
200 out << "break";
201 if (label_ != NULL)
202 out << ' ' << *label_;
203 out << ';';
204 }
205
206 void CYCall::Output(CYOutput &out, CYFlags flags) const {
207 bool protect((flags & CYNoCall) != 0);
208 if (protect)
209 out << '(';
210 function_->Output(out, Precedence(), protect ? CYNoFlags : flags);
211 out << '(' << arguments_ << ')';
212 if (protect)
213 out << ')';
214 }
215
216 void CYCatch::Output(CYOutput &out) const {
217 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ' << code_;
218 }
219
220 void CYCompound::Output(CYOutput &out, CYFlags flags) const {
221 if (CYExpression *expression = expressions_)
222 if (CYExpression *next = expression->next_) {
223 expression->Output(out, CYLeft(flags));
224 CYFlags center(CYCenter(flags));
225 while (next != NULL) {
226 expression = next;
227 out << ',' << ' ';
228 next = expression->next_;
229 CYFlags right(next != NULL ? center : CYRight(flags));
230 expression->Output(out, right);
231 }
232 } else
233 expression->Output(out, flags);
234 }
235
236 void CYCondition::Output(CYOutput &out, CYFlags flags) const {
237 test_->Output(out, Precedence() - 1, CYLeft(flags));
238 out << ' ' << '?' << ' ';
239 if (true_ != NULL)
240 true_->Output(out, CYPA, CYNoFlags);
241 out << ' ' << ':' << ' ';
242 false_->Output(out, CYPA, CYRight(flags));
243 }
244
245 void CYContinue::Output(CYOutput &out, CYFlags flags) const {
246 out << "continue";
247 if (label_ != NULL)
248 out << ' ' << *label_;
249 out << ';';
250 }
251
252 void CYClause::Output(CYOutput &out) const {
253 if (case_ != NULL)
254 out << "case" << ' ' << *case_;
255 else
256 out << "default";
257 out << ':' << '\n';
258 if (statements_ != NULL)
259 statements_->Multiple(out);
260 out << next_;
261 }
262
263 const char *CYDeclaration::ForEachIn() const {
264 return identifier_->Value();
265 }
266
267 void CYDeclaration::ForIn(CYOutput &out, CYFlags flags) const {
268 out << "var";
269 Output(out, CYRight(flags));
270 }
271
272 void CYDeclaration::Output(CYOutput &out, CYFlags flags) const {
273 out << *identifier_;
274 if (initialiser_ != NULL) {
275 out << ' ' << '=' << ' ';
276 initialiser_->Output(out, CYPA, CYRight(flags));
277 }
278 }
279
280 void CYDeclarations::For(CYOutput &out) const {
281 out << "var";
282 Output(out, CYNoIn);
283 }
284
285 void CYDeclarations::Output(CYOutput &out) const {
286 Output(out, CYNoFlags);
287 }
288
289 void CYDeclarations::Output(CYOutput &out, CYFlags flags) const {
290 const CYDeclarations *declaration(this);
291 bool first(true);
292 output:
293 CYDeclarations *next(declaration->next_);
294 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
295 first = false;
296 declaration->declaration_->Output(out, jacks);
297
298 if (next != NULL) {
299 out << ',' << ' ';
300 declaration = next;
301 goto output;
302 }
303 }
304
305 void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
306 object_->Output(out, Precedence(), CYLeft(flags));
307 if (const char *word = property_->Word())
308 out << '.' << word;
309 else
310 out << '[' << *property_ << ']';
311 }
312
313 void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
314 out << "do";
315 code_->Single(out, CYCenter(flags));
316 out << "while" << ' ' << '(' << *test_ << ')';
317 }
318
319 void CYElement::Output(CYOutput &out) const {
320 if (value_ != NULL)
321 value_->Output(out, CYPA, CYNoFlags);
322 if (next_ != NULL || value_ == NULL) {
323 out << ',';
324 if (next_ != NULL && next_->value_ != NULL)
325 out << ' ';
326 }
327 if (next_ != NULL)
328 next_->Output(out);
329 }
330
331 void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
332 out.Terminate();
333 }
334
335 void CYExpress::Output(CYOutput &out, CYFlags flags) const {
336 expression_->Output(out, flags | CYNoBF);
337 out << ';';
338 }
339
340 void CYExpression::ClassName(CYOutput &out, bool object) const {
341 Output(out, CYPA, CYNoFlags);
342 }
343
344 const char *CYExpression::ForEachIn() const {
345 return NULL;
346 }
347
348 void CYExpression::For(CYOutput &out) const {
349 Output(out, CYNoIn);
350 }
351
352 void CYExpression::ForIn(CYOutput &out, CYFlags flags) const {
353 Output(out, flags | CYNoRightHand);
354 }
355
356 void CYExpression::Output(CYOutput &out) const {
357 Output(out, CYNoFlags);
358 }
359
360 void CYExpression::Output(CYOutput &out, unsigned precedence, CYFlags flags) const {
361 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
362 out << '(' << *this << ')';
363 else
364 Output(out, flags);
365 }
366
367 void CYFinally::Output(CYOutput &out) const {
368 out << ' ' << "finally" << ' ' << code_;
369 }
370
371 void CYFor::Output(CYOutput &out, CYFlags flags) const {
372 out << "for" << ' ' << '(';
373 if (initialiser_ != NULL)
374 initialiser_->For(out);
375 out.Terminate();
376 out << test_;
377 out.Terminate();
378 out << increment_;
379 out << ')';
380 code_->Single(out, CYRight(flags));
381 }
382
383 void CYForEachIn::Output(CYOutput &out, CYFlags flags) const {
384 out << "for" << ' ' << "each" << ' ' << '(';
385 initialiser_->ForIn(out, CYNoIn);
386 out << "in" << *set_ << ')';
387 code_->Single(out, CYRight(flags));
388 }
389
390 void CYForEachInComprehension::Output(CYOutput &out) const {
391 out << "for" << ' ' << "each" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')' << next_;
392 }
393
394 void CYForIn::Output(CYOutput &out, CYFlags flags) const {
395 out << "for" << ' ' << '(';
396 initialiser_->ForIn(out, CYNoIn);
397 out << "in" << *set_ << ')';
398 code_->Single(out, CYRight(flags));
399 }
400
401 void CYForInComprehension::Output(CYOutput &out) const {
402 out << "for" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')';
403 }
404
405 void CYFunction::Output(CYOutput &out, CYFlags flags) const {
406 // XXX: one could imagine using + here to save a byte
407 bool protect((flags & CYNoFunction) != 0);
408 if (protect)
409 out << '(';
410 out << "function";
411 if (name_ != NULL)
412 out << ' ' << *name_;
413 out << '(' << parameters_ << ')';
414 out << ' ' << code_;
415 if (protect)
416 out << ')';
417 }
418
419 void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
420 CYFunction::Output(out, flags);
421 }
422
423 void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
424 CYFunction::Output(out, flags);
425 }
426
427 void CYFunctionParameter::Output(CYOutput &out) const {
428 out << *name_;
429 if (next_ != NULL)
430 out << ',' << ' ' << *next_;
431 }
432
433 void CYIf::Output(CYOutput &out, CYFlags flags) const {
434 bool protect(false);
435 if (false_ == NULL && (flags & CYNoDangle) != 0) {
436 protect = true;
437 out << '{';
438 }
439
440 out << "if" << ' ' << '(' << *test_ << ')';
441
442 CYFlags right(protect ? CYNoFlags : CYRight(flags));
443
444 CYFlags jacks(CYNoDangle);
445 if (false_ == NULL)
446 jacks |= right;
447 else
448 jacks |= protect ? CYNoFlags : CYCenter(flags);
449
450 true_->Single(out, jacks);
451
452 if (false_ != NULL) {
453 out << "else";
454 false_->Single(out, right);
455 }
456
457 if (protect)
458 out << '}';
459 }
460
461 void CYIfComprehension::Output(CYOutput &out) const {
462 out << "if" << ' ' << '(' << *test_ << ')' << next_;
463 }
464
465 void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
466 object_->Output(out, Precedence(), CYLeft(flags));
467 if (const char *word = property_->Word())
468 out << "->" << word;
469 else
470 out << "->" << '[' << *property_ << ']';
471 }
472
473 void CYInfix::Output(CYOutput &out, CYFlags flags) const {
474 const char *name(Operator());
475 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
476 if (protect)
477 out << '(';
478 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
479 lhs_->Output(out, Precedence(), left);
480 out << ' ' << name << ' ';
481 CYFlags right(protect ? CYNoFlags : CYRight(flags));
482 rhs_->Output(out, Precedence() - 1, right);
483 if (protect)
484 out << ')';
485 }
486
487 void CYLabel::Output(CYOutput &out, CYFlags flags) const {
488 out << *name_ << ':' << ' ';
489 statement_->Single(out, CYRight(flags));
490 }
491
492 void CYLet::Output(CYOutput &out, CYFlags flags) const {
493 out << "let" << ' ' << '(' << *declarations_ << ')' << ' ' << code_;
494 }
495
496 void CYNew::Output(CYOutput &out, CYFlags flags) const {
497 out << "new" << ' ';
498 CYFlags jacks(CYNoCall | CYCenter(flags));
499 constructor_->Output(out, Precedence(), jacks);
500 if (arguments_ != NULL)
501 out << '(' << *arguments_ << ')';
502 }
503
504 void CYNull::Output(CYOutput &out, CYFlags flags) const {
505 CYWord::Output(out);
506 }
507
508 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
509 char value[32];
510 // XXX: I want this to print 1e3 rather than 1000
511 sprintf(value, "%.17g", Value());
512 out << value;
513 }
514
515 void CYNumber::PropertyName(CYOutput &out) const {
516 Output(out, CYNoFlags);
517 }
518
519 void CYObject::Output(CYOutput &out, CYFlags flags) const {
520 bool protect((flags & CYNoBrace) != 0);
521 if (protect)
522 out << '(';
523 out << '{' << '\n';
524 ++out.indent_;
525 out << properties_;
526 --out.indent_;
527 out << '\t' << '}';
528 if (protect)
529 out << ')';
530 }
531
532 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
533 lhs_->Output(out, Precedence(), CYLeft(flags));
534 out << Operator();
535 }
536
537 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
538 const char *name(Operator());
539 out << name;
540 if (Alphabetic())
541 out << ' ';
542 rhs_->Output(out, Precedence(), CYRight(flags));
543 }
544
545 void CYProgram::Output(CYOutput &out) const {
546 if (statements_ != NULL)
547 statements_->Multiple(out);
548 }
549
550 void CYProperty::Output(CYOutput &out) const {
551 out << '\t';
552 name_->PropertyName(out);
553 out << ':' << ' ';
554 value_->Output(out, CYPA, CYNoFlags);
555 if (next_ != NULL)
556 out << ',' << '\n' << *next_;
557 else
558 out << '\n';
559 }
560
561 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
562 out << Value();
563 }
564
565 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
566 out << "return";
567 if (value_ != NULL)
568 out << ' ' << *value_;
569 out << ';';
570 }
571
572 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
573 bool first(true);
574 for (const CYStatement *next(this); next != NULL; next = next->next_) {
575 bool last(next->next_ == NULL);
576 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYCenter(flags) : CYRight(flags));
577 first = false;
578 out << '\t';
579 next->Output(out, jacks);
580 out << '\n';
581 }
582 }
583
584 void CYStatement::Single(CYOutput &out, CYFlags flags) const {
585 _assert(next_ == NULL);
586 out << '\n';
587 ++out.indent_;
588 out << '\t';
589 Output(out, flags);
590 out << '\n';
591 --out.indent_;
592 }
593
594 void CYString::Output(CYOutput &out, CYFlags flags) const {
595 std::ostringstream str;
596 CYStringify(str, value_, size_);
597 out << str.str().c_str();
598 }
599
600 void CYString::PropertyName(CYOutput &out) const {
601 if (const char *word = Word())
602 out << word;
603 else
604 out << *this;
605 }
606
607 static const char *Reserved_[] = {
608 "false", "null", "true",
609
610 "break", "case", "catch", "continue", "default",
611 "delete", "do", "else", "finally", "for", "function",
612 "if", "in", "instanceof", "new", "return", "switch",
613 "this", "throw", "try", "typeof", "var", "void",
614 "while", "with",
615
616 "debugger", "const",
617
618 "class", "enum", "export", "extends", "import", "super",
619
620 "abstract", "boolean", "byte", "char", "double", "final",
621 "float", "goto", "int", "long", "native", "short",
622 "synchronized", "throws", "transient", "volatile",
623
624 "let", "yield",
625
626 "each",
627
628 NULL
629 };
630
631 const char *CYString::Word() const {
632 if (size_ == 0 || !WordStartRange_[value_[0]])
633 return NULL;
634 for (size_t i(1); i != size_; ++i)
635 if (!WordEndRange_[value_[i]])
636 return NULL;
637 const char *value(Value());
638 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
639 if (strcmp(*reserved, value) == 0)
640 return NULL;
641 return value;
642 }
643
644 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
645 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{';
646 out << clauses_;
647 out << '}';
648 }
649
650 void CYThis::Output(CYOutput &out, CYFlags flags) const {
651 CYWord::Output(out);
652 }
653
654 void CYThrow::Output(CYOutput &out, CYFlags flags) const {
655 out << "throw";
656 if (value_ != NULL)
657 out << ' ' << *value_;
658 out << ';';
659 }
660
661 void CYTry::Output(CYOutput &out, CYFlags flags) const {
662 out << "try" << ' ' << code_ << catch_ << finally_;
663 }
664
665 void CYVar::Output(CYOutput &out, CYFlags flags) const {
666 out << "var";
667 declarations_->Output(out, flags);
668 out << ';';
669 }
670
671 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
672 out << *name_;
673 }
674
675 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
676 out << "while" << '(' << *test_ << ')';
677 code_->Single(out, CYRight(flags));
678 }
679
680 void CYWith::Output(CYOutput &out, CYFlags flags) const {
681 out << "with" << '(' << *scope_ << ')';
682 code_->Single(out, CYRight(flags));
683 }
684
685 void CYWord::ClassName(CYOutput &out, bool object) const {
686 if (object)
687 out << "objc_getClass(";
688 out << '"' << Value() << '"';
689 if (object)
690 out << ')';
691 }
692
693 void CYWord::Output(CYOutput &out) const {
694 out << Value();
695 }
696
697 void CYWord::PropertyName(CYOutput &out) const {
698 Output(out);
699 }