]> git.saurik.com Git - cycript.git/blame_incremental - Output.cpp
Move the various CYFlags helper functions to header.
[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
239const char *CYDeclaration::ForEachIn() const {
240 return identifier_->Word();
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 CYDeclarations::For(CYOutput &out) const {
258 out << "var";
259 Output(out, CYNoIn);
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 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
282void 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
290void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
291 out << "do";
292 code_->Single(out, CYCenter(flags));
293 out << "while" << ' ' << '(' << *test_ << ')';
294}
295
296void 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
308void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
309 out.Terminate();
310}
311
312void CYExpress::Output(CYOutput &out, CYFlags flags) const {
313 expression_->Output(out, flags | CYNoBF);
314 out << ';';
315}
316
317void CYExpression::ClassName(CYOutput &out, bool object) const {
318 Output(out, CYAssign::Precedence_, CYNoFlags);
319}
320
321const char *CYExpression::ForEachIn() const {
322 return NULL;
323}
324
325void CYExpression::For(CYOutput &out) const {
326 Output(out, CYNoIn);
327}
328
329void CYExpression::ForIn(CYOutput &out, CYFlags flags) const {
330 Output(out, flags | CYNoRightHand);
331}
332
333void CYExpression::Output(CYOutput &out) const {
334 Output(out, CYNoFlags);
335}
336
337void 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
344void CYFinally::Output(CYOutput &out) const {
345 out << ' ' << "finally" << ' ' << code_;
346}
347
348void 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
364void 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
371void CYForEachInComprehension::Output(CYOutput &out) const {
372 out << "for" << ' ' << "each" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')' << next_;
373}
374
375void 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
383void CYForInComprehension::Output(CYOutput &out) const {
384 out << "for" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')';
385}
386
387void 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
401void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
402 CYFunction::Output(out, flags);
403}
404
405void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
406 CYFunction::Output(out, flags);
407}
408
409void CYFunctionParameter::Output(CYOutput &out) const {
410 out << *name_;
411 if (next_ != NULL)
412 out << ',' << ' ' << *next_;
413}
414
415const char *CYIdentifier::Word() const {
416 return replace_ == NULL || replace_ == this ? CYWord::Word() : replace_->Word();
417}
418
419void 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
447void CYIfComprehension::Output(CYOutput &out) const {
448 out << "if" << ' ' << '(' << *test_ << ')' << next_;
449}
450
451void 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
459void 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
473void CYLabel::Output(CYOutput &out, CYFlags flags) const {
474 out << *name_ << ':' << ' ';
475 statement_->Single(out, CYRight(flags));
476}
477
478void CYLet::Output(CYOutput &out, CYFlags flags) const {
479 out << "let" << ' ' << '(' << *declarations_ << ')' << ' ' << code_;
480}
481
482namespace cy {
483namespace Syntax {
484
485void 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
495void CYNull::Output(CYOutput &out, CYFlags flags) const {
496 CYWord::Output(out);
497}
498
499void 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
509void CYNumber::PropertyName(CYOutput &out) const {
510 Output(out, CYNoFlags);
511}
512
513void 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
526void CYOptionalFunctionParameter::Output(CYOutput &out) const {
527 out << *name_ << '=';
528 initializer_->Output(out, CYAssign::Precedence_, CYNoFlags);
529 if (next_ != NULL)
530 out << ',' << ' ' << *next_;
531}
532
533void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
534 lhs_->Output(out, Precedence(), CYLeft(flags));
535 out << Operator();
536}
537
538void 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
546void CYProgram::Output(CYOutput &out) const {
547 if (statements_ != NULL)
548 statements_->Multiple(out);
549}
550
551void 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
562void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
563 out << Value();
564}
565
566void CYReturn::Output(CYOutput &out, CYFlags flags) const {
567 out << "return";
568 if (value_ != NULL)
569 out << ' ' << *value_;
570 out << ';';
571}
572
573void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
574 call_->Output(out, CYLeft(flags));
575 out << ' ';
576 proc_->Output(out, CYRight(flags));
577}
578
579void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
580 // XXX: this is not outputting the parameters
581 out << code_;
582}
583
584void 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
596void 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
606void CYString::Output(CYOutput &out, CYFlags flags) const {
607 std::ostringstream str;
608 CYStringify(str, value_, size_);
609 out << str.str().c_str();
610}
611
612void CYString::PropertyName(CYOutput &out) const {
613 if (const char *word = Word())
614 out << word;
615 else
616 out << *this;
617}
618
619static 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
641const 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
654void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
655 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{';
656 out << clauses_;
657 out << '}';
658}
659
660void CYThis::Output(CYOutput &out, CYFlags flags) const {
661 CYWord::Output(out);
662}
663
664namespace cy {
665namespace Syntax {
666
667void Throw::Output(CYOutput &out, CYFlags flags) const {
668 out << "throw";
669 if (value_ != NULL)
670 out << ' ' << *value_;
671 out << ';';
672}
673
674void Try::Output(CYOutput &out, CYFlags flags) const {
675 out << "try" << ' ' << code_ << catch_ << finally_;
676}
677
678} }
679
680void CYVar::Output(CYOutput &out, CYFlags flags) const {
681 out << "var";
682 declarations_->Output(out, flags);
683 out << ';';
684}
685
686void CYVariable::Output(CYOutput &out, CYFlags flags) const {
687 out << *name_;
688}
689
690void CYWhile::Output(CYOutput &out, CYFlags flags) const {
691 out << "while" << '(' << *test_ << ')';
692 code_->Single(out, CYRight(flags));
693}
694
695void CYWith::Output(CYOutput &out, CYFlags flags) const {
696 out << "with" << '(' << *scope_ << ')';
697 code_->Single(out, CYRight(flags));
698}
699
700void CYWord::ClassName(CYOutput &out, bool object) const {
701 if (object)
702 out << "objc_getClass(";
703 out << '"' << Word() << '"';
704 if (object)
705 out << ')';
706}
707
708void CYWord::Output(CYOutput &out) const {
709 out << Word();
710 if (out.options_.verbose_)
711 out.out_ << '@' << this;
712}
713
714void CYWord::PropertyName(CYOutput &out) const {
715 Output(out);
716}
717
718const char *CYWord::Word() const {
719 return word_;
720}