]> git.saurik.com Git - cycript.git/blame_incremental - Output.cpp
Implement CommonJS-compliant require() function.
[cycript.git] / Output.cpp
... / ...
CommitLineData
1/* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2013 Jay Freeman (saurik)
3*/
4
5/* GNU General Public License, Version 3 {{{ */
6/*
7 * Cycript is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 3 of the License,
10 * or (at your option) any later version.
11 *
12 * Cycript is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU 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
27void CYOutput::Terminate() {
28 out_ << ';';
29 mode_ = NoMode;
30}
31
32CYOutput &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
87CYOutput &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
112void 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
127void CYArray::Output(CYOutput &out, CYFlags flags) const {
128 out << '[' << elements_ << ']';
129}
130
131void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
132 out << '[' << *expression_ << ' ' << *comprehensions_ << ']';
133}
134
135void 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
141void 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
150void 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
159void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
160 out << (Value() ? "true" : "false");
161}
162
163void CYBreak::Output(CYOutput &out, CYFlags flags) const {
164 out << "break";
165 if (label_ != NULL)
166 out << ' ' << *label_;
167 out << ';';
168}
169
170void 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
180namespace cy {
181namespace Syntax {
182
183void Catch::Output(CYOutput &out) const {
184 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ' << code_;
185}
186
187} }
188
189void CYComment::Output(CYOutput &out, CYFlags flags) const {
190 out << '\r';
191 out.out_ << value_;
192 out.right_ = true;
193 out << '\r';
194}
195
196void 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
212void 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
221void CYContinue::Output(CYOutput &out, CYFlags flags) const {
222 out << "continue";
223 if (label_ != NULL)
224 out << ' ' << *label_;
225 out << ';';
226}
227
228void 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
239void CYDebugger::Output(CYOutput &out, CYFlags flags) const {
240 out << "debugger" << ';';
241}
242
243void CYDeclaration::ForIn(CYOutput &out, CYFlags flags) const {
244 out << "var";
245 Output(out, CYRight(flags));
246}
247
248void 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
257void CYForDeclarations::Output(CYOutput &out, CYFlags flags) const {
258 out << "var";
259 Output(out, CYRight(flags));
260}
261
262void CYDeclarations::Output(CYOutput &out) const {
263 Output(out, CYNoFlags);
264}
265
266void CYDeclarations::Output(CYOutput &out, CYFlags flags) const {
267 const CYDeclarations *declaration(this);
268 bool first(true);
269
270 for (;;) {
271 CYDeclarations *next(declaration->next_);
272
273 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
274 first = false;
275 declaration->declaration_->Output(out, jacks);
276
277 if (next == NULL)
278 break;
279
280 out << ',' << ' ';
281 declaration = next;
282 }
283}
284
285void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
286 object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger);
287 if (const char *word = property_->Word())
288 out << '.' << word;
289 else
290 out << '[' << *property_ << ']';
291}
292
293void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
294 out << "do";
295 code_->Single(out, CYCenter(flags));
296 out << "while" << ' ' << '(' << *test_ << ')';
297}
298
299void CYElement::Output(CYOutput &out) const {
300 if (value_ != NULL)
301 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
302 if (next_ != NULL || value_ == NULL) {
303 out << ',';
304 if (next_ != NULL && next_->value_ != NULL)
305 out << ' ';
306 }
307 if (next_ != NULL)
308 next_->Output(out);
309}
310
311void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
312 out.Terminate();
313}
314
315void CYExpress::Output(CYOutput &out, CYFlags flags) const {
316 expression_->Output(out, flags | CYNoBF);
317 out << ';';
318}
319
320void CYExpression::ClassName(CYOutput &out, bool object) const {
321 Output(out, CYAssign::Precedence_, CYNoFlags);
322}
323
324void CYExpression::ForIn(CYOutput &out, CYFlags flags) const {
325 Output(out, flags | CYNoRightHand);
326}
327
328void CYExpression::Output(CYOutput &out) const {
329 Output(out, CYNoFlags);
330}
331
332void CYExpression::Output(CYOutput &out, int precedence, CYFlags flags) const {
333 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
334 out << '(' << *this << ')';
335 else
336 Output(out, flags);
337}
338
339void CYFatArrow::Output(CYOutput &out, CYFlags flags) const {
340 out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << code_;
341}
342
343void CYFinally::Output(CYOutput &out) const {
344 out << ' ' << "finally" << ' ' << code_;
345}
346
347void CYFor::Output(CYOutput &out, CYFlags flags) const {
348 out << "for" << ' ' << '(';
349 if (initialiser_ != NULL)
350 initialiser_->Output(out, CYNoIn);
351 out.Terminate();
352 if (test_ != NULL)
353 out << ' ';
354 out << test_;
355 out.Terminate();
356 if (increment_ != NULL)
357 out << ' ';
358 out << increment_;
359 out << ')';
360 code_->Single(out, CYRight(flags));
361}
362
363void CYForOf::Output(CYOutput &out, CYFlags flags) const {
364 out << "for" << ' ' << "each" << ' ' << '(';
365 initialiser_->ForIn(out, CYNoIn);
366 out << "in" << *set_ << ')';
367 code_->Single(out, CYRight(flags));
368}
369
370void CYForOfComprehension::Output(CYOutput &out) const {
371 out << "for" << ' ' << "each" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')' << next_;
372}
373
374void CYForIn::Output(CYOutput &out, CYFlags flags) const {
375 out << "for" << ' ' << '(';
376 if (initialiser_ != NULL)
377 initialiser_->ForIn(out, CYNoIn);
378 out << "in" << *set_ << ')';
379 code_->Single(out, CYRight(flags));
380}
381
382void CYForInComprehension::Output(CYOutput &out) const {
383 out << "for" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')';
384}
385
386void CYFunction::Output(CYOutput &out, CYFlags flags) const {
387 // XXX: one could imagine using + here to save a byte
388 bool protect((flags & CYNoFunction) != 0);
389 if (protect)
390 out << '(';
391 out << "function";
392 if (name_ != NULL)
393 out << ' ' << *name_;
394 out << '(' << parameters_ << ')';
395 out << ' ' << code_;
396 if (protect)
397 out << ')';
398}
399
400void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
401 CYFunction::Output(out, flags);
402}
403
404void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
405 CYFunction::Output(out, flags);
406}
407
408void CYFunctionParameter::Output(CYOutput &out) const {
409 initialiser_->Output(out, CYNoFlags);
410 if (next_ != NULL)
411 out << ',' << ' ' << *next_;
412}
413
414const char *CYIdentifier::Word() const {
415 return replace_ == NULL || replace_ == this ? CYWord::Word() : replace_->Word();
416}
417
418void CYIf::Output(CYOutput &out, CYFlags flags) const {
419 bool protect(false);
420 if (false_ == NULL && (flags & CYNoDangle) != 0) {
421 protect = true;
422 out << '{';
423 }
424
425 out << "if" << ' ' << '(' << *test_ << ')';
426
427 CYFlags right(protect ? CYNoFlags : CYRight(flags));
428
429 CYFlags jacks(CYNoDangle);
430 if (false_ == NULL)
431 jacks |= right;
432 else
433 jacks |= protect ? CYNoFlags : CYCenter(flags);
434
435 true_->Single(out, jacks);
436
437 if (false_ != NULL) {
438 out << '\t' << "else";
439 false_->Single(out, right);
440 }
441
442 if (protect)
443 out << '}';
444}
445
446void CYIfComprehension::Output(CYOutput &out) const {
447 out << "if" << ' ' << '(' << *test_ << ')' << next_;
448}
449
450void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
451 object_->Output(out, Precedence(), CYLeft(flags));
452 if (const char *word = property_->Word())
453 out << "->" << word;
454 else
455 out << "->" << '[' << *property_ << ']';
456}
457
458void CYInfix::Output(CYOutput &out, CYFlags flags) const {
459 const char *name(Operator());
460 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
461 if (protect)
462 out << '(';
463 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
464 lhs_->Output(out, Precedence(), left);
465 out << ' ' << name << ' ';
466 CYFlags right(protect ? CYNoFlags : CYRight(flags));
467 rhs_->Output(out, Precedence() - 1, right);
468 if (protect)
469 out << ')';
470}
471
472void CYLabel::Output(CYOutput &out, CYFlags flags) const {
473 out << *name_ << ':' << ' ';
474 statement_->Single(out, CYRight(flags));
475}
476
477void CYTypeArrayOf::Output(CYOutput &out, CYIdentifier *identifier) const {
478 next_->Output(out, Precedence(), identifier);
479 out << '[';
480 out << size_;
481 out << ']';
482}
483
484void CYTypeConstant::Output(CYOutput &out, CYIdentifier *identifier) const {
485 out << "const";
486 next_->Output(out, Precedence(), identifier);
487}
488
489void CYTypeFunctionWith::Output(CYOutput &out, CYIdentifier *identifier) const {
490 next_->Output(out, Precedence(), identifier);
491 out << '(' << parameters_ << ')';
492}
493
494void CYTypePointerTo::Output(CYOutput &out, CYIdentifier *identifier) const {
495 out << '*';
496 next_->Output(out, Precedence(), identifier);
497}
498
499void CYTypeVolatile::Output(CYOutput &out, CYIdentifier *identifier) const {
500 out << "volatile";
501 next_->Output(out, Precedence(), identifier);
502}
503
504void CYTypeModifier::Output(CYOutput &out, int precedence, CYIdentifier *identifier) const {
505 if (this == NULL) {
506 out << identifier;
507 return;
508 }
509
510 bool protect(precedence > Precedence());
511
512 if (protect)
513 out << '(';
514 Output(out, identifier);
515 if (protect)
516 out << ')';
517}
518
519void CYTypedIdentifier::Output(CYOutput &out) const {
520 type_->Output(out, 0, CYNoFlags);
521 modifier_->Output(out, 0, identifier_);
522}
523
524void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
525 out << "@encode(" << typed_ << ")";
526}
527
528void CYTypedParameter::Output(CYOutput &out) const {
529 out << typed_;
530 if (next_ != NULL)
531 out << ',' << ' ' << next_;
532}
533
534void CYLambda::Output(CYOutput &out, CYFlags flags) const {
535 // XXX: this is seriously wrong
536 out << "[](";
537 out << ")->";
538 out << "{";
539 out << "}";
540}
541
542void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
543 out << "typedef" << *typed_;
544}
545
546void CYLetStatement::Output(CYOutput &out, CYFlags flags) const {
547 out << "let" << ' ' << '(' << *declarations_ << ')';
548 code_->Single(out, CYRight(flags));
549}
550
551namespace cy {
552namespace Syntax {
553
554void New::Output(CYOutput &out, CYFlags flags) const {
555 out << "new" << ' ';
556 CYFlags jacks(CYNoCall | CYCenter(flags));
557 constructor_->Output(out, Precedence(), jacks);
558 if (arguments_ != NULL)
559 out << '(' << *arguments_ << ')';
560}
561
562} }
563
564void CYNull::Output(CYOutput &out, CYFlags flags) const {
565 CYWord::Output(out);
566}
567
568void CYNumber::Output(CYOutput &out, CYFlags flags) const {
569 std::ostringstream str;
570 CYNumerify(str, Value());
571 std::string value(str.str());
572 out << value.c_str();
573 // XXX: this should probably also handle hex conversions and exponents
574 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
575 out << '.';
576}
577
578void CYNumber::PropertyName(CYOutput &out) const {
579 Output(out, CYNoFlags);
580}
581
582void CYObject::Output(CYOutput &out, CYFlags flags) const {
583 bool protect((flags & CYNoBrace) != 0);
584 if (protect)
585 out << '(';
586 out << '{' << '\n';
587 ++out.indent_;
588 out << properties_;
589 --out.indent_;
590 out << '\t' << '}';
591 if (protect)
592 out << ')';
593}
594
595void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
596 lhs_->Output(out, Precedence(), CYLeft(flags));
597 out << Operator();
598}
599
600void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
601 const char *name(Operator());
602 out << name;
603 if (Alphabetic())
604 out << ' ';
605 rhs_->Output(out, Precedence(), CYRight(flags));
606}
607
608void CYProgram::Output(CYOutput &out) const {
609 if (statements_ != NULL)
610 statements_->Multiple(out);
611}
612
613void CYProperty::Output(CYOutput &out) const {
614 out << '\t';
615 name_->PropertyName(out);
616 out << ':' << ' ';
617 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
618 if (next_ != NULL)
619 out << ',' << '\n' << *next_;
620 else
621 out << '\n';
622}
623
624void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
625 out << Value();
626}
627
628void CYReturn::Output(CYOutput &out, CYFlags flags) const {
629 out << "return";
630 if (value_ != NULL)
631 out << ' ' << *value_;
632 out << ';';
633}
634
635void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
636 call_->Output(out, CYLeft(flags));
637 out << ' ';
638 proc_->Output(out, CYRight(flags));
639}
640
641void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
642 // XXX: this is not outputting the parameters
643 out << code_;
644}
645
646void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
647 bool first(true);
648 CYForEach (next, this) {
649 bool last(next->next_ == NULL);
650 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
651 first = false;
652 out << '\t';
653 next->Output(out, jacks);
654 out << '\n';
655 }
656}
657
658void CYStatement::Single(CYOutput &out, CYFlags flags) const {
659 if (this == NULL)
660 return out.Terminate();
661
662 _assert(next_ == NULL);
663 out << '\n';
664 ++out.indent_;
665 out << '\t';
666 Output(out, flags);
667 out << '\n';
668 --out.indent_;
669}
670
671void CYString::Output(CYOutput &out, CYFlags flags) const {
672 std::ostringstream str;
673 CYStringify(str, value_, size_);
674 out << str.str().c_str();
675}
676
677void CYString::PropertyName(CYOutput &out) const {
678 if (const char *word = Word())
679 out << word;
680 else
681 out << *this;
682}
683
684static const char *Reserved_[] = {
685 "false", "null", "true",
686
687 "break", "case", "catch", "continue", "default",
688 "delete", "do", "else", "finally", "for", "function",
689 "if", "in", "instanceof", "new", "return", "switch",
690 "this", "throw", "try", "typeof", "var", "void",
691 "while", "with",
692
693 "debugger", "const",
694
695 "class", "enum", "export", "extends", "import", "super",
696
697 "abstract", "boolean", "byte", "char", "double", "final",
698 "float", "goto", "int", "long", "native", "short",
699 "synchronized", "throws", "transient", "volatile",
700
701 "let", "yield",
702
703 NULL
704};
705
706const char *CYString::Word() const {
707 if (size_ == 0 || !WordStartRange_[value_[0]])
708 return NULL;
709 for (size_t i(1); i != size_; ++i)
710 if (!WordEndRange_[value_[i]])
711 return NULL;
712 const char *value(Value());
713 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
714 if (strcmp(*reserved, value) == 0)
715 return NULL;
716 return value;
717}
718
719void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
720 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{';
721 out << clauses_;
722 out << '}';
723}
724
725void CYThis::Output(CYOutput &out, CYFlags flags) const {
726 CYWord::Output(out);
727}
728
729namespace cy {
730namespace Syntax {
731
732void Throw::Output(CYOutput &out, CYFlags flags) const {
733 out << "throw";
734 if (value_ != NULL)
735 out << ' ' << *value_;
736 out << ';';
737}
738
739void Try::Output(CYOutput &out, CYFlags flags) const {
740 out << "try" << ' ' << code_ << catch_ << finally_;
741}
742
743} }
744
745void CYVar::Output(CYOutput &out, CYFlags flags) const {
746 out << "var";
747 declarations_->Output(out, flags);
748 out << ';';
749}
750
751void CYVariable::Output(CYOutput &out, CYFlags flags) const {
752 out << *name_;
753}
754
755void CYWhile::Output(CYOutput &out, CYFlags flags) const {
756 out << "while" << '(' << *test_ << ')';
757 code_->Single(out, CYRight(flags));
758}
759
760void CYWith::Output(CYOutput &out, CYFlags flags) const {
761 out << "with" << '(' << *scope_ << ')';
762 code_->Single(out, CYRight(flags));
763}
764
765void CYWord::ClassName(CYOutput &out, bool object) const {
766 if (object)
767 out << "objc_getClass(";
768 out << '"' << Word() << '"';
769 if (object)
770 out << ')';
771}
772
773void CYWord::Output(CYOutput &out) const {
774 out << Word();
775 if (out.options_.verbose_)
776 out.out_ << '@' << this;
777}
778
779void CYWord::PropertyName(CYOutput &out) const {
780 Output(out);
781}
782
783const char *CYWord::Word() const {
784 return word_;
785}