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