]> git.saurik.com Git - cycript.git/blame_incremental - Output.cpp
Fixed a minor bug introduced today in CYClause serialization.
[cycript.git] / Output.cpp
... / ...
CommitLineData
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
34void CYOutput::Terminate() {
35 out_ << ';';
36 mode_ = NoMode;
37}
38
39CYOutput &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
85CYOutput &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
109void 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
124void CYArray::Output(CYOutput &out, CYFlags flags) const {
125 out << '[' << elements_ << ']';
126}
127
128void 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
146void 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
152void 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
161void 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
170void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
171 out << (Value() ? "true" : "false");
172}
173
174void CYBreak::Output(CYOutput &out, CYFlags flags) const {
175 out << "break";
176 if (label_ != NULL)
177 out << ' ' << *label_;
178 out << ';';
179}
180
181void 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
191void CYCatch::Output(CYOutput &out) const {
192 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ' << code_;
193}
194
195void 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
211void CYComprehension::Output(CYOutput &out) const {
212 Begin_(out);
213 out << next_;
214}
215
216void 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
225void CYContinue::Output(CYOutput &out, CYFlags flags) const {
226 out << "continue";
227 if (label_ != NULL)
228 out << ' ' << *label_;
229 out << ';';
230}
231
232void 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
243const char *CYDeclaration::ForEachIn() const {
244 return identifier_->Value();
245}
246
247void CYDeclaration::ForIn(CYOutput &out, CYFlags flags) const {
248 out << "var";
249 Output(out, CYRight(flags));
250}
251
252void CYDeclaration::ForEachIn(CYOutput &out) const {
253 out << *identifier_;
254}
255
256void 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
264void CYDeclarations::For(CYOutput &out) const {
265 out << "var";
266 Output(out, CYNoIn);
267}
268
269void CYDeclarations::Output(CYOutput &out) const {
270 Output(out, CYNoFlags);
271}
272
273void 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
289void 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
297void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
298 out << "do";
299 code_->Single(out, CYCenter(flags));
300 out << "while" << ' ' << '(' << *test_ << ')';
301}
302
303void 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
315void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
316 out.Terminate();
317}
318
319void CYExpress::Output(CYOutput &out, CYFlags flags) const {
320 expression_->Output(out, flags | CYNoBF);
321 out << ';';
322}
323
324void CYExpression::ClassName(CYOutput &out, bool object) const {
325 Output(out, CYPA, CYNoFlags);
326}
327
328const char *CYExpression::ForEachIn() const {
329 return NULL;
330}
331
332void CYExpression::For(CYOutput &out) const {
333 Output(out, CYNoIn);
334}
335
336void CYExpression::ForEachIn(CYOutput &out) const {
337 Output(out, CYPA, CYNoRightHand);
338}
339
340void CYExpression::ForIn(CYOutput &out, CYFlags flags) const {
341 Output(out, flags | CYNoRightHand);
342}
343
344void CYExpression::Output(CYOutput &out) const {
345 Output(out, CYNoFlags);
346}
347
348void 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
355void CYFinally::Output(CYOutput &out) const {
356 out << ' ' << "finally" << ' ' << code_;
357}
358
359void 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
371void 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
390void 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
400void CYForEachInComprehension::End_(CYOutput &out) const {
401 out << "}}());";
402}
403
404void 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
411void CYForInComprehension::Begin_(CYOutput &out) const {
412 out << "for" << ' ' << '(' << *name_ << "in" << *set_ << ')';
413}
414
415void 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
429void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
430 CYFunction::Output(out, flags);
431}
432
433void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
434 CYFunction::Output(out, flags);
435}
436
437void CYFunctionParameter::Output(CYOutput &out) const {
438 out << *name_;
439 if (next_ != NULL)
440 out << ',' << ' ' << *next_;
441}
442
443void 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
471void CYIfComprehension::Begin_(CYOutput &out) const {
472 out << "if" << '(' << *test_ << ')';
473}
474
475void 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
483void 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
497void CYLabel::Output(CYOutput &out, CYFlags flags) const {
498 out << *name_ << ':' << ' ';
499 statement_->Single(out, CYRight(flags));
500}
501
502void CYLet::Output(CYOutput &out, CYFlags flags) const {
503 out << "let" << ' ' << '(' << *declarations_ << ')' << ' ' << code_;
504}
505
506void 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
514void CYNull::Output(CYOutput &out, CYFlags flags) const {
515 CYWord::Output(out);
516}
517
518void CYNumber::Output(CYOutput &out, CYFlags flags) const {
519 char value[32];
520 sprintf(value, "%.17g", Value());
521 out << value;
522}
523
524void CYNumber::PropertyName(CYOutput &out) const {
525 Output(out, CYNoFlags);
526}
527
528void 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
541void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
542 lhs_->Output(out, Precedence(), CYLeft(flags));
543 out << Operator();
544}
545
546void 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
554void CYProgram::Output(CYOutput &out) const {
555 if (statements_ != NULL)
556 statements_->Multiple(out);
557}
558
559void 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
570void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
571 out << Value();
572}
573
574void CYReturn::Output(CYOutput &out, CYFlags flags) const {
575 out << "return";
576 if (value_ != NULL)
577 out << ' ' << *value_;
578 out << ';';
579}
580
581void 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
593void 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
603void 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
649void CYString::PropertyName(CYOutput &out) const {
650 if (const char *word = Word())
651 out << word;
652 else
653 out << *this;
654}
655
656static 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
680const 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
693void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
694 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{';
695 out << clauses_;
696 out << '}';
697}
698
699void CYThis::Output(CYOutput &out, CYFlags flags) const {
700 CYWord::Output(out);
701}
702
703void CYThrow::Output(CYOutput &out, CYFlags flags) const {
704 out << "throw";
705 if (value_ != NULL)
706 out << ' ' << *value_;
707 out << ';';
708}
709
710void CYTry::Output(CYOutput &out, CYFlags flags) const {
711 out << "try" << ' ' << code_ << catch_ << finally_;
712}
713
714void CYVar::Output(CYOutput &out, CYFlags flags) const {
715 out << "var";
716 declarations_->Output(out, flags);
717 out << ';';
718}
719
720void CYVariable::Output(CYOutput &out, CYFlags flags) const {
721 out << *name_;
722}
723
724void CYWhile::Output(CYOutput &out, CYFlags flags) const {
725 out << "while" << '(' << *test_ << ')';
726 code_->Single(out, CYRight(flags));
727}
728
729void CYWith::Output(CYOutput &out, CYFlags flags) const {
730 out << "with" << '(' << *scope_ << ')';
731 code_->Single(out, CYRight(flags));
732}
733
734void CYWord::ClassName(CYOutput &out, bool object) const {
735 if (object)
736 out << "objc_getClass(";
737 out << '"' << Value() << '"';
738 if (object)
739 out << ')';
740}
741
742void CYWord::Output(CYOutput &out) const {
743 out << Value();
744}
745
746void CYWord::PropertyName(CYOutput &out) const {
747 Output(out);
748}