]> git.saurik.com Git - cycript.git/blob - Output.cpp
I don't understand what the hell is wrong with Apple's compiler, but it does not...
[cycript.git] / Output.cpp
1 /* Cycript - Inlining/Optimizing JavaScript Compiler
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 namespace cy {
217 namespace Syntax {
218
219 void Catch::Output(CYOutput &out) const {
220 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ' << code_;
221 }
222
223 } }
224
225 void CYCompound::Output(CYOutput &out, CYFlags flags) const {
226 if (CYExpression *expression = expressions_)
227 if (CYExpression *next = expression->next_) {
228 expression->Output(out, CYLeft(flags));
229 CYFlags center(CYCenter(flags));
230 while (next != NULL) {
231 expression = next;
232 out << ',' << ' ';
233 next = expression->next_;
234 CYFlags right(next != NULL ? center : CYRight(flags));
235 expression->Output(out, right);
236 }
237 } else
238 expression->Output(out, flags);
239 }
240
241 void CYCondition::Output(CYOutput &out, CYFlags flags) const {
242 test_->Output(out, Precedence() - 1, CYLeft(flags));
243 out << ' ' << '?' << ' ';
244 if (true_ != NULL)
245 true_->Output(out, CYPA, CYNoFlags);
246 out << ' ' << ':' << ' ';
247 false_->Output(out, CYPA, CYRight(flags));
248 }
249
250 void CYContinue::Output(CYOutput &out, CYFlags flags) const {
251 out << "continue";
252 if (label_ != NULL)
253 out << ' ' << *label_;
254 out << ';';
255 }
256
257 void CYClause::Output(CYOutput &out) const {
258 if (case_ != NULL)
259 out << "case" << ' ' << *case_;
260 else
261 out << "default";
262 out << ':' << '\n';
263 if (statements_ != NULL)
264 statements_->Multiple(out);
265 out << next_;
266 }
267
268 const char *CYDeclaration::ForEachIn() const {
269 return identifier_->Value();
270 }
271
272 void CYDeclaration::ForIn(CYOutput &out, CYFlags flags) const {
273 out << "var";
274 Output(out, CYRight(flags));
275 }
276
277 void CYDeclaration::Output(CYOutput &out, CYFlags flags) const {
278 out << *identifier_;
279 if (initialiser_ != NULL) {
280 out << ' ' << '=' << ' ';
281 initialiser_->Output(out, CYPA, CYRight(flags));
282 }
283 }
284
285 void CYDeclarations::For(CYOutput &out) const {
286 out << "var";
287 Output(out, CYNoIn);
288 }
289
290 void CYDeclarations::Output(CYOutput &out) const {
291 Output(out, CYNoFlags);
292 }
293
294 void CYDeclarations::Output(CYOutput &out, CYFlags flags) const {
295 const CYDeclarations *declaration(this);
296 bool first(true);
297 output:
298 CYDeclarations *next(declaration->next_);
299 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
300 first = false;
301 declaration->declaration_->Output(out, jacks);
302
303 if (next != NULL) {
304 out << ',' << ' ';
305 declaration = next;
306 goto output;
307 }
308 }
309
310 void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
311 object_->Output(out, Precedence(), CYLeft(flags));
312 if (const char *word = property_->Word())
313 out << '.' << word;
314 else
315 out << '[' << *property_ << ']';
316 }
317
318 void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
319 out << "do";
320 code_->Single(out, CYCenter(flags));
321 out << "while" << ' ' << '(' << *test_ << ')';
322 }
323
324 void CYElement::Output(CYOutput &out) const {
325 if (value_ != NULL)
326 value_->Output(out, CYPA, CYNoFlags);
327 if (next_ != NULL || value_ == NULL) {
328 out << ',';
329 if (next_ != NULL && next_->value_ != NULL)
330 out << ' ';
331 }
332 if (next_ != NULL)
333 next_->Output(out);
334 }
335
336 void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
337 out.Terminate();
338 }
339
340 void CYExpress::Output(CYOutput &out, CYFlags flags) const {
341 expression_->Output(out, flags | CYNoBF);
342 out << ';';
343 }
344
345 void CYExpression::ClassName(CYOutput &out, bool object) const {
346 Output(out, CYPA, CYNoFlags);
347 }
348
349 const char *CYExpression::ForEachIn() const {
350 return NULL;
351 }
352
353 void CYExpression::For(CYOutput &out) const {
354 Output(out, CYNoIn);
355 }
356
357 void CYExpression::ForIn(CYOutput &out, CYFlags flags) const {
358 Output(out, flags | CYNoRightHand);
359 }
360
361 void CYExpression::Output(CYOutput &out) const {
362 Output(out, CYNoFlags);
363 }
364
365 void CYExpression::Output(CYOutput &out, unsigned precedence, CYFlags flags) const {
366 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
367 out << '(' << *this << ')';
368 else
369 Output(out, flags);
370 }
371
372 void CYFinally::Output(CYOutput &out) const {
373 out << ' ' << "finally" << ' ' << code_;
374 }
375
376 void CYFor::Output(CYOutput &out, CYFlags flags) const {
377 out << "for" << ' ' << '(';
378 if (initialiser_ != NULL)
379 initialiser_->For(out);
380 out.Terminate();
381 out << test_;
382 out.Terminate();
383 out << increment_;
384 out << ')';
385 code_->Single(out, CYRight(flags));
386 }
387
388 void CYForEachIn::Output(CYOutput &out, CYFlags flags) const {
389 out << "for" << ' ' << "each" << ' ' << '(';
390 initialiser_->ForIn(out, CYNoIn);
391 out << "in" << *set_ << ')';
392 code_->Single(out, CYRight(flags));
393 }
394
395 void CYForEachInComprehension::Output(CYOutput &out) const {
396 out << "for" << ' ' << "each" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')' << next_;
397 }
398
399 void CYForIn::Output(CYOutput &out, CYFlags flags) const {
400 out << "for" << ' ' << '(';
401 initialiser_->ForIn(out, CYNoIn);
402 out << "in" << *set_ << ')';
403 code_->Single(out, CYRight(flags));
404 }
405
406 void CYForInComprehension::Output(CYOutput &out) const {
407 out << "for" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')';
408 }
409
410 void CYFunction::Output(CYOutput &out, CYFlags flags) const {
411 // XXX: one could imagine using + here to save a byte
412 bool protect((flags & CYNoFunction) != 0);
413 if (protect)
414 out << '(';
415 out << "function";
416 if (name_ != NULL)
417 out << ' ' << *name_;
418 out << '(' << parameters_ << ')';
419 out << ' ' << code_;
420 if (protect)
421 out << ')';
422 }
423
424 void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
425 CYFunction::Output(out, flags);
426 }
427
428 void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
429 CYFunction::Output(out, flags);
430 }
431
432 void CYFunctionParameter::Output(CYOutput &out) const {
433 out << *name_;
434 if (next_ != NULL)
435 out << ',' << ' ' << *next_;
436 }
437
438 void CYIf::Output(CYOutput &out, CYFlags flags) const {
439 bool protect(false);
440 if (false_ == NULL && (flags & CYNoDangle) != 0) {
441 protect = true;
442 out << '{';
443 }
444
445 out << "if" << ' ' << '(' << *test_ << ')';
446
447 CYFlags right(protect ? CYNoFlags : CYRight(flags));
448
449 CYFlags jacks(CYNoDangle);
450 if (false_ == NULL)
451 jacks |= right;
452 else
453 jacks |= protect ? CYNoFlags : CYCenter(flags);
454
455 true_->Single(out, jacks);
456
457 if (false_ != NULL) {
458 out << "else";
459 false_->Single(out, right);
460 }
461
462 if (protect)
463 out << '}';
464 }
465
466 void CYIfComprehension::Output(CYOutput &out) const {
467 out << "if" << ' ' << '(' << *test_ << ')' << next_;
468 }
469
470 void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
471 object_->Output(out, Precedence(), CYLeft(flags));
472 if (const char *word = property_->Word())
473 out << "->" << word;
474 else
475 out << "->" << '[' << *property_ << ']';
476 }
477
478 void CYInfix::Output(CYOutput &out, CYFlags flags) const {
479 const char *name(Operator());
480 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
481 if (protect)
482 out << '(';
483 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
484 lhs_->Output(out, Precedence(), left);
485 out << ' ' << name << ' ';
486 CYFlags right(protect ? CYNoFlags : CYRight(flags));
487 rhs_->Output(out, Precedence() - 1, right);
488 if (protect)
489 out << ')';
490 }
491
492 void CYLabel::Output(CYOutput &out, CYFlags flags) const {
493 out << *name_ << ':' << ' ';
494 statement_->Single(out, CYRight(flags));
495 }
496
497 void CYLet::Output(CYOutput &out, CYFlags flags) const {
498 out << "let" << ' ' << '(' << *declarations_ << ')' << ' ' << code_;
499 }
500
501 void CYNew::Output(CYOutput &out, CYFlags flags) const {
502 out << "new" << ' ';
503 CYFlags jacks(CYNoCall | CYCenter(flags));
504 constructor_->Output(out, Precedence(), jacks);
505 if (arguments_ != NULL)
506 out << '(' << *arguments_ << ')';
507 }
508
509 void CYNull::Output(CYOutput &out, CYFlags flags) const {
510 CYWord::Output(out);
511 }
512
513 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
514 std::ostringstream str;
515 CYNumerify(str, Value());
516 out << str.str().c_str();
517 }
518
519 void CYNumber::PropertyName(CYOutput &out) const {
520 Output(out, CYNoFlags);
521 }
522
523 void CYObject::Output(CYOutput &out, CYFlags flags) const {
524 bool protect((flags & CYNoBrace) != 0);
525 if (protect)
526 out << '(';
527 out << '{' << '\n';
528 ++out.indent_;
529 out << properties_;
530 --out.indent_;
531 out << '\t' << '}';
532 if (protect)
533 out << ')';
534 }
535
536 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
537 lhs_->Output(out, Precedence(), CYLeft(flags));
538 out << Operator();
539 }
540
541 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
542 const char *name(Operator());
543 out << name;
544 if (Alphabetic())
545 out << ' ';
546 rhs_->Output(out, Precedence(), CYRight(flags));
547 }
548
549 void CYProgram::Output(CYOutput &out) const {
550 if (statements_ != NULL)
551 statements_->Multiple(out);
552 }
553
554 void CYProperty::Output(CYOutput &out) const {
555 out << '\t';
556 name_->PropertyName(out);
557 out << ':' << ' ';
558 value_->Output(out, CYPA, CYNoFlags);
559 if (next_ != NULL)
560 out << ',' << '\n' << *next_;
561 else
562 out << '\n';
563 }
564
565 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
566 out << Value();
567 }
568
569 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
570 out << "return";
571 if (value_ != NULL)
572 out << ' ' << *value_;
573 out << ';';
574 }
575
576 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
577 bool first(true);
578 for (const CYStatement *next(this); next != NULL; next = next->next_) {
579 bool last(next->next_ == NULL);
580 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYCenter(flags) : CYRight(flags));
581 first = false;
582 out << '\t';
583 next->Output(out, jacks);
584 out << '\n';
585 }
586 }
587
588 void CYStatement::Single(CYOutput &out, CYFlags flags) const {
589 _assert(next_ == NULL);
590 out << '\n';
591 ++out.indent_;
592 out << '\t';
593 Output(out, flags);
594 out << '\n';
595 --out.indent_;
596 }
597
598 void CYString::Output(CYOutput &out, CYFlags flags) const {
599 std::ostringstream str;
600 CYStringify(str, value_, size_);
601 out << str.str().c_str();
602 }
603
604 void CYString::PropertyName(CYOutput &out) const {
605 if (const char *word = Word())
606 out << word;
607 else
608 out << *this;
609 }
610
611 static const char *Reserved_[] = {
612 "false", "null", "true",
613
614 "break", "case", "catch", "continue", "default",
615 "delete", "do", "else", "finally", "for", "function",
616 "if", "in", "instanceof", "new", "return", "switch",
617 "this", "throw", "try", "typeof", "var", "void",
618 "while", "with",
619
620 "debugger", "const",
621
622 "class", "enum", "export", "extends", "import", "super",
623
624 "abstract", "boolean", "byte", "char", "double", "final",
625 "float", "goto", "int", "long", "native", "short",
626 "synchronized", "throws", "transient", "volatile",
627
628 "let", "yield",
629
630 "each",
631
632 NULL
633 };
634
635 const char *CYString::Word() const {
636 if (size_ == 0 || !WordStartRange_[value_[0]])
637 return NULL;
638 for (size_t i(1); i != size_; ++i)
639 if (!WordEndRange_[value_[i]])
640 return NULL;
641 const char *value(Value());
642 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
643 if (strcmp(*reserved, value) == 0)
644 return NULL;
645 return value;
646 }
647
648 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
649 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{';
650 out << clauses_;
651 out << '}';
652 }
653
654 void CYThis::Output(CYOutput &out, CYFlags flags) const {
655 CYWord::Output(out);
656 }
657
658 namespace cy {
659 namespace Syntax {
660
661 void Throw::Output(CYOutput &out, CYFlags flags) const {
662 out << "throw";
663 if (value_ != NULL)
664 out << ' ' << *value_;
665 out << ';';
666 }
667
668 void Try::Output(CYOutput &out, CYFlags flags) const {
669 out << "try" << ' ' << code_ << catch_ << finally_;
670 }
671
672 } }
673
674 void CYVar::Output(CYOutput &out, CYFlags flags) const {
675 out << "var";
676 declarations_->Output(out, flags);
677 out << ';';
678 }
679
680 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
681 out << *name_;
682 }
683
684 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
685 out << "while" << '(' << *test_ << ')';
686 code_->Single(out, CYRight(flags));
687 }
688
689 void CYWith::Output(CYOutput &out, CYFlags flags) const {
690 out << "with" << '(' << *scope_ << ')';
691 code_->Single(out, CYRight(flags));
692 }
693
694 void CYWord::ClassName(CYOutput &out, bool object) const {
695 if (object)
696 out << "objc_getClass(";
697 out << '"' << Value() << '"';
698 if (object)
699 out << ')';
700 }
701
702 void CYWord::Output(CYOutput &out) const {
703 out << Value();
704 }
705
706 void CYWord::PropertyName(CYOutput &out) const {
707 Output(out);
708 }