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