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