]> git.saurik.com Git - cycript.git/blob - Output.cpp
9ffc4f67037e790067db5ce971bd00d503f0eb94
[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 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 std::string value(str.str());
517 out << value.c_str();
518 // XXX: this should probably also handle hex conversions and exponents
519 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
520 out << '.';
521 }
522
523 void CYNumber::PropertyName(CYOutput &out) const {
524 Output(out, CYNoFlags);
525 }
526
527 void CYObject::Output(CYOutput &out, CYFlags flags) const {
528 bool protect((flags & CYNoBrace) != 0);
529 if (protect)
530 out << '(';
531 out << '{' << '\n';
532 ++out.indent_;
533 out << properties_;
534 --out.indent_;
535 out << '\t' << '}';
536 if (protect)
537 out << ')';
538 }
539
540 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
541 lhs_->Output(out, Precedence(), CYLeft(flags));
542 out << Operator();
543 }
544
545 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
546 const char *name(Operator());
547 out << name;
548 if (Alphabetic())
549 out << ' ';
550 rhs_->Output(out, Precedence(), CYRight(flags));
551 }
552
553 void CYProgram::Output(CYOutput &out) const {
554 if (statements_ != NULL)
555 statements_->Multiple(out);
556 }
557
558 void CYProperty::Output(CYOutput &out) const {
559 out << '\t';
560 name_->PropertyName(out);
561 out << ':' << ' ';
562 value_->Output(out, CYPA, CYNoFlags);
563 if (next_ != NULL)
564 out << ',' << '\n' << *next_;
565 else
566 out << '\n';
567 }
568
569 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
570 out << Value();
571 }
572
573 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
574 out << "return";
575 if (value_ != NULL)
576 out << ' ' << *value_;
577 out << ';';
578 }
579
580 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
581 bool first(true);
582 for (const CYStatement *next(this); next != NULL; next = next->next_) {
583 bool last(next->next_ == NULL);
584 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYCenter(flags) : CYRight(flags));
585 first = false;
586 out << '\t';
587 next->Output(out, jacks);
588 out << '\n';
589 }
590 }
591
592 void CYStatement::Single(CYOutput &out, CYFlags flags) const {
593 _assert(next_ == NULL);
594 out << '\n';
595 ++out.indent_;
596 out << '\t';
597 Output(out, flags);
598 out << '\n';
599 --out.indent_;
600 }
601
602 void CYString::Output(CYOutput &out, CYFlags flags) const {
603 std::ostringstream str;
604 CYStringify(str, value_, size_);
605 out << str.str().c_str();
606 }
607
608 void CYString::PropertyName(CYOutput &out) const {
609 if (const char *word = Word())
610 out << word;
611 else
612 out << *this;
613 }
614
615 static const char *Reserved_[] = {
616 "false", "null", "true",
617
618 "break", "case", "catch", "continue", "default",
619 "delete", "do", "else", "finally", "for", "function",
620 "if", "in", "instanceof", "new", "return", "switch",
621 "this", "throw", "try", "typeof", "var", "void",
622 "while", "with",
623
624 "debugger", "const",
625
626 "class", "enum", "export", "extends", "import", "super",
627
628 "abstract", "boolean", "byte", "char", "double", "final",
629 "float", "goto", "int", "long", "native", "short",
630 "synchronized", "throws", "transient", "volatile",
631
632 "let", "yield",
633
634 "each",
635
636 NULL
637 };
638
639 const char *CYString::Word() const {
640 if (size_ == 0 || !WordStartRange_[value_[0]])
641 return NULL;
642 for (size_t i(1); i != size_; ++i)
643 if (!WordEndRange_[value_[i]])
644 return NULL;
645 const char *value(Value());
646 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
647 if (strcmp(*reserved, value) == 0)
648 return NULL;
649 return value;
650 }
651
652 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
653 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{';
654 out << clauses_;
655 out << '}';
656 }
657
658 void CYThis::Output(CYOutput &out, CYFlags flags) const {
659 CYWord::Output(out);
660 }
661
662 namespace cy {
663 namespace Syntax {
664
665 void Throw::Output(CYOutput &out, CYFlags flags) const {
666 out << "throw";
667 if (value_ != NULL)
668 out << ' ' << *value_;
669 out << ';';
670 }
671
672 void Try::Output(CYOutput &out, CYFlags flags) const {
673 out << "try" << ' ' << code_ << catch_ << finally_;
674 }
675
676 } }
677
678 void CYVar::Output(CYOutput &out, CYFlags flags) const {
679 out << "var";
680 declarations_->Output(out, flags);
681 out << ';';
682 }
683
684 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
685 out << *name_;
686 }
687
688 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
689 out << "while" << '(' << *test_ << ')';
690 code_->Single(out, CYRight(flags));
691 }
692
693 void CYWith::Output(CYOutput &out, CYFlags flags) const {
694 out << "with" << '(' << *scope_ << ')';
695 code_->Single(out, CYRight(flags));
696 }
697
698 void CYWord::ClassName(CYOutput &out, bool object) const {
699 if (object)
700 out << "objc_getClass(";
701 out << '"' << Value() << '"';
702 if (object)
703 out << ')';
704 }
705
706 void CYWord::Output(CYOutput &out) const {
707 out << Value();
708 }
709
710 void CYWord::PropertyName(CYOutput &out) const {
711 Output(out);
712 }