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