]> git.saurik.com Git - cycript.git/blob - Output.cpp
Started working on variable name replacement strategies and generally improved compiler.
[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_->Word();
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 << '`';
356 out.Terminate();
357 }
358
359 void CYExpress::Output(CYOutput &out, CYFlags flags) const {
360 expression_->Output(out, flags | CYNoBF);
361 out << ';';
362 }
363
364 void CYExpression::ClassName(CYOutput &out, bool object) const {
365 Output(out, CYPA, CYNoFlags);
366 }
367
368 const char *CYExpression::ForEachIn() const {
369 return NULL;
370 }
371
372 void CYExpression::For(CYOutput &out) const {
373 Output(out, CYNoIn);
374 }
375
376 void CYExpression::ForIn(CYOutput &out, CYFlags flags) const {
377 Output(out, flags | CYNoRightHand);
378 }
379
380 void CYExpression::Output(CYOutput &out) const {
381 Output(out, CYNoFlags);
382 }
383
384 void CYExpression::Output(CYOutput &out, unsigned precedence, CYFlags flags) const {
385 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
386 out << '(' << *this << ')';
387 else
388 Output(out, flags);
389 }
390
391 void CYFinally::Output(CYOutput &out) const {
392 out << ' ' << "finally" << ' ' << code_;
393 }
394
395 void CYFor::Output(CYOutput &out, CYFlags flags) const {
396 out << "for" << ' ' << '(';
397 if (initialiser_ != NULL)
398 initialiser_->For(out);
399 out.Terminate();
400 out << test_;
401 out.Terminate();
402 out << increment_;
403 out << ')';
404 code_->Single(out, CYRight(flags));
405 }
406
407 void CYForEachIn::Output(CYOutput &out, CYFlags flags) const {
408 out << "for" << ' ' << "each" << ' ' << '(';
409 initialiser_->ForIn(out, CYNoIn);
410 out << "in" << *set_ << ')';
411 code_->Single(out, CYRight(flags));
412 }
413
414 void CYForEachInComprehension::Output(CYOutput &out) const {
415 out << "for" << ' ' << "each" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')' << next_;
416 }
417
418 void CYForIn::Output(CYOutput &out, CYFlags flags) const {
419 out << "for" << ' ' << '(';
420 if (initialiser_ != NULL)
421 initialiser_->ForIn(out, CYNoIn);
422 out << "in" << *set_ << ')';
423 code_->Single(out, CYRight(flags));
424 }
425
426 void CYForInComprehension::Output(CYOutput &out) const {
427 out << "for" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')';
428 }
429
430 void CYFunction::Output(CYOutput &out, CYFlags flags) const {
431 // XXX: one could imagine using + here to save a byte
432 bool protect((flags & CYNoFunction) != 0);
433 if (protect)
434 out << '(';
435 out << "function";
436 if (out.options_.verbose_)
437 out.out_ << ':' << static_cast<const CYScope *>(this);
438 if (name_ != NULL)
439 out << ' ' << *name_;
440 out << '(' << parameters_ << ')';
441 out << ' ' << code_;
442 if (protect)
443 out << ')';
444 }
445
446 void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
447 CYFunction::Output(out, flags);
448 }
449
450 void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
451 CYFunction::Output(out, flags);
452 }
453
454 void CYFunctionParameter::Output(CYOutput &out) const {
455 out << *name_;
456 if (next_ != NULL)
457 out << ',' << ' ' << *next_;
458 }
459
460 const char *CYIdentifier::Word() const {
461 return replace_ == NULL || replace_ == this ? CYWord::Word() : replace_->Word();
462 }
463
464 void CYIf::Output(CYOutput &out, CYFlags flags) const {
465 bool protect(false);
466 if (false_ == NULL && (flags & CYNoDangle) != 0) {
467 protect = true;
468 out << '{';
469 }
470
471 out << "if" << ' ' << '(' << *test_ << ')';
472
473 CYFlags right(protect ? CYNoFlags : CYRight(flags));
474
475 CYFlags jacks(CYNoDangle);
476 if (false_ == NULL)
477 jacks |= right;
478 else
479 jacks |= protect ? CYNoFlags : CYCenter(flags);
480
481 true_->Single(out, jacks);
482
483 if (false_ != NULL) {
484 out << "else";
485 false_->Single(out, right);
486 }
487
488 if (protect)
489 out << '}';
490 }
491
492 void CYIfComprehension::Output(CYOutput &out) const {
493 out << "if" << ' ' << '(' << *test_ << ')' << next_;
494 }
495
496 void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
497 object_->Output(out, Precedence(), CYLeft(flags));
498 if (const char *word = property_->Word())
499 out << "->" << word;
500 else
501 out << "->" << '[' << *property_ << ']';
502 }
503
504 void CYInfix::Output(CYOutput &out, CYFlags flags) const {
505 const char *name(Operator());
506 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
507 if (protect)
508 out << '(';
509 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
510 lhs_->Output(out, Precedence(), left);
511 out << ' ' << name << ' ';
512 CYFlags right(protect ? CYNoFlags : CYRight(flags));
513 rhs_->Output(out, Precedence() - 1, right);
514 if (protect)
515 out << ')';
516 }
517
518 void CYLabel::Output(CYOutput &out, CYFlags flags) const {
519 out << *name_ << ':' << ' ';
520 statement_->Single(out, CYRight(flags));
521 }
522
523 void CYLet::Output(CYOutput &out, CYFlags flags) const {
524 out << "let" << ' ' << '(' << *declarations_ << ')' << ' ' << code_;
525 }
526
527 void CYNew::Output(CYOutput &out, CYFlags flags) const {
528 out << "new" << ' ';
529 CYFlags jacks(CYNoCall | CYCenter(flags));
530 constructor_->Output(out, Precedence(), jacks);
531 if (arguments_ != NULL)
532 out << '(' << *arguments_ << ')';
533 }
534
535 void CYNull::Output(CYOutput &out, CYFlags flags) const {
536 CYWord::Output(out);
537 }
538
539 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
540 std::ostringstream str;
541 CYNumerify(str, Value());
542 std::string value(str.str());
543 out << value.c_str();
544 // XXX: this should probably also handle hex conversions and exponents
545 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
546 out << '.';
547 }
548
549 void CYNumber::PropertyName(CYOutput &out) const {
550 Output(out, CYNoFlags);
551 }
552
553 void CYObject::Output(CYOutput &out, CYFlags flags) const {
554 bool protect((flags & CYNoBrace) != 0);
555 if (protect)
556 out << '(';
557 out << '{' << '\n';
558 ++out.indent_;
559 out << properties_;
560 --out.indent_;
561 out << '\t' << '}';
562 if (protect)
563 out << ')';
564 }
565
566 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
567 lhs_->Output(out, Precedence(), CYLeft(flags));
568 out << Operator();
569 }
570
571 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
572 const char *name(Operator());
573 out << name;
574 if (Alphabetic())
575 out << ' ';
576 rhs_->Output(out, Precedence(), CYRight(flags));
577 }
578
579 void CYProgram::Output(CYOutput &out) const {
580 if (statements_ != NULL)
581 statements_->Multiple(out);
582 }
583
584 void CYProperty::Output(CYOutput &out) const {
585 out << '\t';
586 name_->PropertyName(out);
587 out << ':' << ' ';
588 value_->Output(out, CYPA, CYNoFlags);
589 if (next_ != NULL)
590 out << ',' << '\n' << *next_;
591 else
592 out << '\n';
593 }
594
595 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
596 out << Value();
597 }
598
599 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
600 out << "return";
601 if (value_ != NULL)
602 out << ' ' << *value_;
603 out << ';';
604 }
605
606 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
607 bool first(true);
608 for (const CYStatement *next(this); next != NULL; next = next->next_) {
609 bool last(next->next_ == NULL);
610 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYCenter(flags) : CYRight(flags));
611 first = false;
612 out << '\t';
613 next->Output(out, jacks);
614 out << '\n';
615 }
616 }
617
618 void CYStatement::Single(CYOutput &out, CYFlags flags) const {
619 _assert(next_ == NULL);
620 out << '\n';
621 ++out.indent_;
622 out << '\t';
623 Output(out, flags);
624 out << '\n';
625 --out.indent_;
626 }
627
628 void CYString::Output(CYOutput &out, CYFlags flags) const {
629 std::ostringstream str;
630 CYStringify(str, value_, size_);
631 out << str.str().c_str();
632 }
633
634 void CYString::PropertyName(CYOutput &out) const {
635 if (const char *word = Word())
636 out << word;
637 else
638 out << *this;
639 }
640
641 static const char *Reserved_[] = {
642 "false", "null", "true",
643
644 "break", "case", "catch", "continue", "default",
645 "delete", "do", "else", "finally", "for", "function",
646 "if", "in", "instanceof", "new", "return", "switch",
647 "this", "throw", "try", "typeof", "var", "void",
648 "while", "with",
649
650 "debugger", "const",
651
652 "class", "enum", "export", "extends", "import", "super",
653
654 "abstract", "boolean", "byte", "char", "double", "final",
655 "float", "goto", "int", "long", "native", "short",
656 "synchronized", "throws", "transient", "volatile",
657
658 "let", "yield",
659
660 "each",
661
662 NULL
663 };
664
665 const char *CYString::Word() const {
666 if (size_ == 0 || !WordStartRange_[value_[0]])
667 return NULL;
668 for (size_t i(1); i != size_; ++i)
669 if (!WordEndRange_[value_[i]])
670 return NULL;
671 const char *value(Value());
672 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
673 if (strcmp(*reserved, value) == 0)
674 return NULL;
675 return value;
676 }
677
678 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
679 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{';
680 out << clauses_;
681 out << '}';
682 }
683
684 void CYThis::Output(CYOutput &out, CYFlags flags) const {
685 CYWord::Output(out);
686 }
687
688 namespace cy {
689 namespace Syntax {
690
691 void Throw::Output(CYOutput &out, CYFlags flags) const {
692 out << "throw";
693 if (value_ != NULL)
694 out << ' ' << *value_;
695 out << ';';
696 }
697
698 void Try::Output(CYOutput &out, CYFlags flags) const {
699 out << "try" << ' ' << code_ << catch_ << finally_;
700 }
701
702 } }
703
704 void CYVar::Output(CYOutput &out, CYFlags flags) const {
705 out << "var";
706 declarations_->Output(out, flags);
707 out << ';';
708 }
709
710 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
711 out << *name_;
712 }
713
714 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
715 out << "while" << '(' << *test_ << ')';
716 code_->Single(out, CYRight(flags));
717 }
718
719 void CYWith::Output(CYOutput &out, CYFlags flags) const {
720 out << "with" << '(' << *scope_ << ')';
721 code_->Single(out, CYRight(flags));
722 }
723
724 void CYWord::ClassName(CYOutput &out, bool object) const {
725 if (object)
726 out << "objc_getClass(";
727 out << '"' << Word() << '"';
728 if (object)
729 out << ')';
730 }
731
732 void CYWord::Output(CYOutput &out) const {
733 out << Word();
734 if (out.options_.verbose_)
735 out.out_ << '@' << this;
736 }
737
738 void CYWord::PropertyName(CYOutput &out) const {
739 Output(out);
740 }
741
742 const char *CYWord::Word() const {
743 return word_;
744 }