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