]> git.saurik.com Git - cycript.git/blob - Output.cpp
Hide complicated hold manipulation behind CYHLD().
[cycript.git] / Output.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <cmath>
23 #include <iomanip>
24 #include <sstream>
25
26 #include "Syntax.hpp"
27
28 void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c) {
29 bool single;
30 if (c)
31 single = false;
32 else {
33 unsigned quot(0), apos(0);
34 for (const char *value(data), *end(data + size); value != end; ++value)
35 if (*value == '"')
36 ++quot;
37 else if (*value == '\'')
38 ++apos;
39
40 single = quot > apos;
41 }
42
43 str << (single ? '\'' : '"');
44
45 for (const char *value(data), *end(data + size); value != end; ++value)
46 switch (uint8_t next = *value) {
47 case '\\': str << "\\\\"; break;
48 case '\b': str << "\\b"; break;
49 case '\f': str << "\\f"; break;
50 case '\n': str << "\\n"; break;
51 case '\r': str << "\\r"; break;
52 case '\t': str << "\\t"; break;
53 case '\v': str << "\\v"; break;
54
55 case '"':
56 if (!single)
57 str << "\\\"";
58 else goto simple;
59 break;
60
61 case '\'':
62 if (single)
63 str << "\\'";
64 else goto simple;
65 break;
66
67 case '\0':
68 if (value[1] >= '0' && value[1] <= '9')
69 str << "\\x00";
70 else
71 str << "\\0";
72 break;
73
74 default:
75 if (next >= 0x20 && next < 0x7f) simple:
76 str << *value;
77 else {
78 unsigned levels(1);
79 if ((next & 0x80) != 0)
80 while ((next & 0x80 >> ++levels) != 0);
81
82 unsigned point(next & 0xff >> levels);
83 while (--levels != 0)
84 point = point << 6 | uint8_t(*++value) & 0x3f;
85
86 if (point < 0x100)
87 str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << point;
88 else if (point < 0x10000)
89 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << point;
90 else {
91 point -= 0x10000;
92 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xd800 | point >> 0x0a);
93 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xdc00 | point & 0x3ff);
94 }
95 }
96 }
97
98 str << (single ? '\'' : '"');
99 }
100
101 void CYNumerify(std::ostringstream &str, double value) {
102 if (std::isinf(value)) {
103 if (value < 0)
104 str << '-';
105 str << "Infinity";
106 return;
107 }
108
109 char string[32];
110 // XXX: I want this to print 1e3 rather than 1000
111 sprintf(string, "%.17g", value);
112 str << string;
113 }
114
115 void CYOutput::Terminate() {
116 operator ()(';');
117 mode_ = NoMode;
118 }
119
120 CYOutput &CYOutput::operator <<(char rhs) {
121 if (rhs == ' ' || rhs == '\n')
122 if (pretty_)
123 operator ()(rhs);
124 else goto done;
125 else if (rhs == '\t')
126 if (pretty_)
127 for (unsigned i(0); i != indent_; ++i)
128 operator ()(" ", 4);
129 else goto done;
130 else if (rhs == '\r') {
131 if (right_) {
132 operator ()('\n');
133 right_ = false;
134 } goto done;
135 } else goto work;
136
137 right_ = true;
138 mode_ = NoMode;
139 goto done;
140
141 work:
142 if (mode_ == Terminated && rhs != '}') {
143 right_ = true;
144 operator ()(';');
145 }
146
147 if (rhs == ';') {
148 if (pretty_)
149 goto none;
150 else {
151 mode_ = Terminated;
152 goto done;
153 }
154 } else if (rhs == '+') {
155 if (mode_ == NoPlus)
156 operator ()(' ');
157 mode_ = NoPlus;
158 } else if (rhs == '-') {
159 if (mode_ == NoHyphen)
160 operator ()(' ');
161 mode_ = NoHyphen;
162 } else if (WordEndRange_[rhs]) {
163 if (mode_ == NoLetter)
164 operator ()(' ');
165 mode_ = NoLetter;
166 } else none:
167 mode_ = NoMode;
168
169 right_ = true;
170 operator ()(rhs);
171 done:
172 return *this;
173 }
174
175 CYOutput &CYOutput::operator <<(const char *rhs) {
176 size_t size(strlen(rhs));
177
178 if (size == 1)
179 return *this << *rhs;
180
181 if (mode_ == Terminated)
182 operator ()(';');
183 else if (
184 mode_ == NoPlus && *rhs == '+' ||
185 mode_ == NoHyphen && *rhs == '-' ||
186 mode_ == NoLetter && WordEndRange_[*rhs]
187 )
188 operator ()(' ');
189
190 char last(rhs[size - 1]);
191 if (WordEndRange_[last] || last == '/')
192 mode_ = NoLetter;
193 else
194 mode_ = NoMode;
195
196 right_ = true;
197 operator ()(rhs, size);
198 return *this;
199 }
200
201 void CYArgument::Output(CYOutput &out) const {
202 if (name_ != NULL) {
203 out << *name_;
204 if (value_ != NULL)
205 out << ':' << ' ';
206 }
207 if (value_ != NULL)
208 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
209 if (next_ != NULL) {
210 out << ',';
211 out << ' ' << *next_;
212 }
213 }
214
215 void CYArray::Output(CYOutput &out, CYFlags flags) const {
216 out << '[' << elements_ << ']';
217 }
218
219 void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
220 out << '[' << *expression_ << ' ' << *comprehensions_ << ']';
221 }
222
223 void CYAssignment::Output(CYOutput &out, CYFlags flags) const {
224 lhs_->Output(out, Precedence() - 1, CYLeft(flags) | CYNoRightHand);
225 out << ' ' << Operator() << ' ';
226 rhs_->Output(out, Precedence(), CYRight(flags));
227 }
228
229 void CYBlock::Output(CYOutput &out, CYFlags flags) const {
230 out << '{' << '\n';
231 ++out.indent_;
232 out << code_;
233 --out.indent_;
234 out << '\t' << '}';
235 }
236
237 void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
238 out << '!' << (Value() ? "0" : "1");
239 if ((flags & CYNoInteger) != 0)
240 out << '.';
241 }
242
243 void CYBreak::Output(CYOutput &out, CYFlags flags) const {
244 out << "break";
245 if (label_ != NULL)
246 out << ' ' << *label_;
247 out << ';';
248 }
249
250 void CYCall::Output(CYOutput &out, CYFlags flags) const {
251 bool protect((flags & CYNoCall) != 0);
252 if (protect)
253 out << '(';
254 function_->Output(out, Precedence(), protect ? CYNoFlags : flags);
255 out << '(' << arguments_ << ')';
256 if (protect)
257 out << ')';
258 }
259
260 namespace cy {
261 namespace Syntax {
262
263 void Catch::Output(CYOutput &out) const {
264 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ';
265 out << '{' << '\n';
266 ++out.indent_;
267 out << code_;
268 --out.indent_;
269 out << '\t' << '}';
270 }
271
272 } }
273
274 void CYClassExpression::Output(CYOutput &out, CYFlags flags) const {
275 bool protect((flags & CYNoClass) != 0);
276 if (protect)
277 out << '(';
278 out << "class";
279 if (name_ != NULL)
280 out << ' ' << *name_;
281 out << *tail_;;
282 if (protect)
283 out << ')';
284 }
285
286 void CYClassStatement::Output(CYOutput &out, CYFlags flags) const {
287 out << "class" << ' ' << *name_ << *tail_;
288 }
289
290 void CYClassTail::Output(CYOutput &out) const {
291 if (extends_ == NULL)
292 out << ' ';
293 else {
294 out << '\n';
295 ++out.indent_;
296 out << "extends" << ' ';
297 extends_->Output(out, CYAssign::Precedence_ - 1, CYNoFlags);
298 out << '\n';
299 --out.indent_;
300 }
301
302 out << '{' << '\n';
303 ++out.indent_;
304
305 --out.indent_;
306 out << '}';
307 }
308
309 void CYCompound::Output(CYOutput &out, CYFlags flags) const {
310 if (next_ == NULL)
311 expression_->Output(out, flags);
312 else {
313 expression_->Output(out, CYLeft(flags));
314 out << ',' << ' ';
315 next_->Output(out, CYRight(flags));
316 }
317 }
318
319 void CYComputed::PropertyName(CYOutput &out) const {
320 out << '[';
321 expression_->Output(out, CYAssign::Precedence_, CYNoFlags);
322 out << ']';
323 }
324
325 void CYCondition::Output(CYOutput &out, CYFlags flags) const {
326 test_->Output(out, Precedence() - 1, CYLeft(flags));
327 out << ' ' << '?' << ' ';
328 if (true_ != NULL)
329 true_->Output(out, CYAssign::Precedence_, CYNoColon);
330 out << ' ' << ':' << ' ';
331 false_->Output(out, CYAssign::Precedence_, CYRight(flags));
332 }
333
334 void CYContinue::Output(CYOutput &out, CYFlags flags) const {
335 out << "continue";
336 if (label_ != NULL)
337 out << ' ' << *label_;
338 out << ';';
339 }
340
341 void CYClause::Output(CYOutput &out) const {
342 out << '\t';
343 if (value_ == NULL)
344 out << "default";
345 else {
346 out << "case" << ' ';
347 value_->Output(out, CYNoColon);
348 }
349 out << ':' << '\n';
350 ++out.indent_;
351 out << code_;
352 --out.indent_;
353 out << next_;
354 }
355
356 void CYDebugger::Output(CYOutput &out, CYFlags flags) const {
357 out << "debugger" << ';';
358 }
359
360 void CYBinding::Output(CYOutput &out, CYFlags flags) const {
361 out << *identifier_;
362 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
363 if (initializer_ != NULL) {
364 out << ' ' << '=' << ' ';
365 initializer_->Output(out, CYAssign::Precedence_, CYRight(flags));
366 }
367 }
368
369 void CYBindings::Output(CYOutput &out) const {
370 Output(out, CYNoFlags);
371 }
372
373 void CYBindings::Output(CYOutput &out, CYFlags flags) const {
374 const CYBindings *binding(this);
375 bool first(true);
376
377 for (;;) {
378 CYBindings *next(binding->next_);
379
380 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
381 first = false;
382 binding->binding_->Output(out, jacks);
383
384 if (next == NULL)
385 break;
386
387 out << ',' << ' ';
388 binding = next;
389 }
390 }
391
392 void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
393 object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger);
394 if (const char *word = property_->Word())
395 out << '.' << word;
396 else
397 out << '[' << *property_ << ']';
398 }
399
400 void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
401 out << "do";
402
403 unsigned line(out.position_.line);
404 unsigned indent(out.indent_);
405 code_->Single(out, CYCenter(flags), CYCompactLong);
406
407 if (out.position_.line != line && out.recent_ == indent)
408 out << ' ';
409 else
410 out << '\n' << '\t';
411
412 out << "while" << ' ' << '(' << *test_ << ')';
413 }
414
415 void CYElementSpread::Output(CYOutput &out) const {
416 out << "..." << value_;
417 }
418
419 void CYElementValue::Output(CYOutput &out) const {
420 if (value_ != NULL)
421 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
422 if (next_ != NULL || value_ == NULL) {
423 out << ',';
424 if (next_ != NULL && !next_->Elision())
425 out << ' ';
426 }
427 if (next_ != NULL)
428 next_->Output(out);
429 }
430
431 void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
432 out.Terminate();
433 }
434
435 void CYEval::Output(CYOutput &out, CYFlags flags) const {
436 _assert(false);
437 }
438
439 void CYExpress::Output(CYOutput &out, CYFlags flags) const {
440 expression_->Output(out, flags | CYNoBFC);
441 out << ';';
442 }
443
444 void CYExpression::Output(CYOutput &out) const {
445 Output(out, CYNoFlags);
446 }
447
448 void CYExpression::Output(CYOutput &out, int precedence, CYFlags flags) const {
449 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
450 out << '(' << *this << ')';
451 else
452 Output(out, flags);
453 }
454
455 void CYExternal::Output(CYOutput &out, CYFlags flags) const {
456 out << "extern" << abi_ << typed_;
457 out.Terminate();
458 }
459
460 void CYFatArrow::Output(CYOutput &out, CYFlags flags) const {
461 out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << '{' << code_ << '}';
462 }
463
464 void CYFinally::Output(CYOutput &out) const {
465 out << ' ' << "finally" << ' ';
466 out << '{' << '\n';
467 ++out.indent_;
468 out << code_;
469 --out.indent_;
470 out << '\t' << '}';
471 }
472
473 void CYFor::Output(CYOutput &out, CYFlags flags) const {
474 out << "for" << ' ' << '(';
475 if (initializer_ != NULL)
476 initializer_->Output(out, CYNoIn);
477 out.Terminate();
478 if (test_ != NULL)
479 out << ' ';
480 out << test_;
481 out.Terminate();
482 if (increment_ != NULL)
483 out << ' ';
484 out << increment_;
485 out << ')';
486 code_->Single(out, CYRight(flags), CYCompactShort);
487 }
488
489 void CYForLexical::Output(CYOutput &out, CYFlags flags) const {
490 out << (constant_ ? "const" : "let") << ' ';
491 binding_->Output(out, CYRight(flags));
492 }
493
494 void CYForIn::Output(CYOutput &out, CYFlags flags) const {
495 out << "for" << ' ' << '(';
496 initializer_->Output(out, CYNoIn | CYNoRightHand);
497 out << ' ' << "in" << ' ' << *iterable_ << ')';
498 code_->Single(out, CYRight(flags), CYCompactShort);
499 }
500
501 void CYForInitialized::Output(CYOutput &out, CYFlags flags) const {
502 out << "for" << ' ' << '(' << "var" << ' ';
503 binding_->Output(out, CYNoIn | CYNoRightHand);
504 out << ' ' << "in" << ' ' << *iterable_ << ')';
505 code_->Single(out, CYRight(flags), CYCompactShort);
506 }
507
508 void CYForInComprehension::Output(CYOutput &out) const {
509 out << "for" << ' ' << '(';
510 binding_->Output(out, CYNoIn | CYNoRightHand);
511 out << ' ' << "in" << ' ' << *iterable_ << ')';
512 }
513
514 void CYForOf::Output(CYOutput &out, CYFlags flags) const {
515 out << "for" << ' ' << '(';
516 initializer_->Output(out, CYNoRightHand);
517 out << ' ' << "of" << ' ' << *iterable_ << ')';
518 code_->Single(out, CYRight(flags), CYCompactShort);
519 }
520
521 void CYForOfComprehension::Output(CYOutput &out) const {
522 out << "for" << ' ' << '(';
523 binding_->Output(out, CYNoRightHand);
524 out << ' ' << "of" << ' ' << *iterable_ << ')' << next_;
525 }
526
527 void CYForVariable::Output(CYOutput &out, CYFlags flags) const {
528 out << "var" << ' ';
529 binding_->Output(out, CYRight(flags));
530 }
531
532 void CYFunction::Output(CYOutput &out) const {
533 out << '(' << parameters_ << ')' << ' ';
534 out << '{' << '\n';
535 ++out.indent_;
536 out << code_;
537 --out.indent_;
538 out << '\t' << '}';
539 }
540
541 void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
542 // XXX: one could imagine using + here to save a byte
543 bool protect((flags & CYNoFunction) != 0);
544 if (protect)
545 out << '(';
546 out << "function";
547 if (name_ != NULL)
548 out << ' ' << *name_;
549 CYFunction::Output(out);
550 if (protect)
551 out << ')';
552 }
553
554 void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
555 out << "function" << ' ' << *name_;
556 CYFunction::Output(out);
557 }
558
559 void CYFunctionParameter::Output(CYOutput &out) const {
560 binding_->Output(out, CYNoFlags);
561 if (next_ != NULL)
562 out << ',' << ' ' << *next_;
563 }
564
565 const char *CYIdentifier::Word() const {
566 return next_ == NULL || next_ == this ? CYWord::Word() : next_->Word();
567 }
568
569 void CYIf::Output(CYOutput &out, CYFlags flags) const {
570 bool protect(false);
571 if (false_ == NULL && (flags & CYNoDangle) != 0) {
572 protect = true;
573 out << '{';
574 }
575
576 out << "if" << ' ' << '(' << *test_ << ')';
577
578 CYFlags right(protect ? CYNoFlags : CYRight(flags));
579
580 CYFlags jacks(CYNoDangle);
581 if (false_ == NULL)
582 jacks |= right;
583 else
584 jacks |= protect ? CYNoFlags : CYCenter(flags);
585
586 unsigned line(out.position_.line);
587 unsigned indent(out.indent_);
588 true_->Single(out, jacks, CYCompactShort);
589
590 if (false_ != NULL) {
591 if (out.position_.line != line && out.recent_ == indent)
592 out << ' ';
593 else
594 out << '\n' << '\t';
595
596 out << "else";
597 false_->Single(out, right, CYCompactLong);
598 }
599
600 if (protect)
601 out << '}';
602 }
603
604 void CYIfComprehension::Output(CYOutput &out) const {
605 out << "if" << ' ' << '(' << *test_ << ')' << next_;
606 }
607
608 void CYImport::Output(CYOutput &out, CYFlags flags) const {
609 out << "@import";
610 }
611
612 void CYImportDeclaration::Output(CYOutput &out, CYFlags flags) const {
613 _assert(false);
614 }
615
616 void CYIndirect::Output(CYOutput &out, CYFlags flags) const {
617 out << "*";
618 rhs_->Output(out, Precedence(), CYRight(flags));
619 }
620
621 void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
622 object_->Output(out, Precedence(), CYLeft(flags));
623 if (const char *word = property_->Word())
624 out << "->" << word;
625 else
626 out << "->" << '[' << *property_ << ']';
627 }
628
629 void CYInfix::Output(CYOutput &out, CYFlags flags) const {
630 const char *name(Operator());
631 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
632 if (protect)
633 out << '(';
634 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
635 lhs_->Output(out, Precedence(), left);
636 out << ' ' << name << ' ';
637 CYFlags right(protect ? CYNoFlags : CYRight(flags));
638 rhs_->Output(out, Precedence() - 1, right);
639 if (protect)
640 out << ')';
641 }
642
643 void CYLabel::Output(CYOutput &out, CYFlags flags) const {
644 out << *name_ << ':';
645 statement_->Single(out, CYRight(flags), CYCompactShort);
646 }
647
648 void CYParenthetical::Output(CYOutput &out, CYFlags flags) const {
649 out << '(';
650 expression_->Output(out, CYCompound::Precedence_, CYNoFlags);
651 out << ')';
652 }
653
654 void CYStatement::Output(CYOutput &out) const {
655 Multiple(out);
656 }
657
658 void CYTemplate::Output(CYOutput &out, CYFlags flags) const {
659 _assert(false);
660 }
661
662 void CYTypeArrayOf::Output(CYOutput &out, CYIdentifier *identifier) const {
663 next_->Output(out, Precedence(), identifier);
664 out << '[';
665 out << size_;
666 out << ']';
667 }
668
669 void CYTypeBlockWith::Output(CYOutput &out, CYIdentifier *identifier) const {
670 out << '(' << '^';
671 next_->Output(out, Precedence(), identifier);
672 out << ')' << '(' << parameters_ << ')';
673 }
674
675 void CYTypeConstant::Output(CYOutput &out, CYIdentifier *identifier) const {
676 out << "const" << ' ';
677 next_->Output(out, Precedence(), identifier);
678 }
679
680 void CYTypeFunctionWith::Output(CYOutput &out, CYIdentifier *identifier) const {
681 next_->Output(out, Precedence(), identifier);
682 out << '(' << parameters_;
683 if (variadic_) {
684 if (parameters_ != NULL)
685 out << ',' << ' ';
686 out << "...";
687 }
688 out << ')';
689 }
690
691 void CYTypePointerTo::Output(CYOutput &out, CYIdentifier *identifier) const {
692 out << '*';
693 next_->Output(out, Precedence(), identifier);
694 }
695
696 void CYTypeVolatile::Output(CYOutput &out, CYIdentifier *identifier) const {
697 out << "volatile";
698 next_->Output(out, Precedence(), identifier);
699 }
700
701 void CYTypeModifier::Output(CYOutput &out, int precedence, CYIdentifier *identifier) const {
702 if (this == NULL) {
703 out << identifier;
704 return;
705 }
706
707 bool protect(precedence > Precedence());
708
709 if (protect)
710 out << '(';
711 Output(out, identifier);
712 if (protect)
713 out << ')';
714 }
715
716 void CYTypedIdentifier::Output(CYOutput &out) const {
717 specifier_->Output(out);
718 modifier_->Output(out, 0, identifier_);
719 }
720
721 void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
722 out << "@encode(" << typed_ << ")";
723 }
724
725 void CYTypedParameter::Output(CYOutput &out) const {
726 out << typed_;
727 if (next_ != NULL)
728 out << ',' << ' ' << next_;
729 }
730
731 void CYLambda::Output(CYOutput &out, CYFlags flags) const {
732 // XXX: this is seriously wrong
733 out << "[](";
734 out << ")->";
735 out << "{";
736 out << "}";
737 }
738
739 void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
740 out << "typedef" << ' ' << *typed_;
741 out.Terminate();
742 }
743
744 void CYTypeExpression::Output(CYOutput &out, CYFlags flags) const {
745 out << '(' << "typedef" << ' ' << *typed_ << ')';
746 }
747
748 void CYLexical::Output(CYOutput &out, CYFlags flags) const {
749 out << "let" << ' ';
750 bindings_->Output(out, flags); // XXX: flags
751 out << ';';
752 }
753
754 void CYModule::Output(CYOutput &out) const {
755 out << part_;
756 if (next_ != NULL)
757 out << '.' << next_;
758 }
759
760 namespace cy {
761 namespace Syntax {
762
763 void New::Output(CYOutput &out, CYFlags flags) const {
764 out << "new" << ' ';
765 CYFlags jacks(CYNoCall | CYCenter(flags));
766 constructor_->Output(out, Precedence(), jacks);
767 if (arguments_ != NULL)
768 out << '(' << *arguments_ << ')';
769 }
770
771 } }
772
773 void CYNull::Output(CYOutput &out, CYFlags flags) const {
774 out << "null";
775 }
776
777 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
778 std::ostringstream str;
779 CYNumerify(str, Value());
780 std::string value(str.str());
781 out << value.c_str();
782 // XXX: this should probably also handle hex conversions and exponents
783 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
784 out << '.';
785 }
786
787 void CYNumber::PropertyName(CYOutput &out) const {
788 Output(out, CYNoFlags);
789 }
790
791 void CYObject::Output(CYOutput &out, CYFlags flags) const {
792 bool protect((flags & CYNoBrace) != 0);
793 if (protect)
794 out << '(';
795 out << '{' << '\n';
796 ++out.indent_;
797 out << properties_;
798 --out.indent_;
799 out << '\t' << '}';
800 if (protect)
801 out << ')';
802 }
803
804 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
805 lhs_->Output(out, Precedence(), CYLeft(flags));
806 out << Operator();
807 }
808
809 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
810 const char *name(Operator());
811 out << name;
812 if (Alphabetic())
813 out << ' ';
814 rhs_->Output(out, Precedence(), CYRight(flags));
815 }
816
817 void CYScript::Output(CYOutput &out) const {
818 out << code_;
819 }
820
821 void CYProperty::Output(CYOutput &out) const {
822 if (next_ != NULL || out.pretty_)
823 out << ',';
824 out << '\n' << next_;
825 }
826
827 void CYPropertyGetter::Output(CYOutput &out) const {
828 out << "get" << ' ';
829 name_->PropertyName(out);
830 CYFunction::Output(out);
831 CYProperty::Output(out);
832 }
833
834 void CYPropertyMethod::Output(CYOutput &out) const {
835 name_->PropertyName(out);
836 CYFunction::Output(out);
837 CYProperty::Output(out);
838 }
839
840 void CYPropertySetter::Output(CYOutput &out) const {
841 out << "set" << ' ';
842 name_->PropertyName(out);
843 CYFunction::Output(out);
844 CYProperty::Output(out);
845 }
846
847 void CYPropertyValue::Output(CYOutput &out) const {
848 out << '\t';
849 name_->PropertyName(out);
850 out << ':' << ' ';
851 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
852 CYProperty::Output(out);
853 }
854
855 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
856 out << Value();
857 }
858
859 void CYResolveMember::Output(CYOutput &out, CYFlags flags) const {
860 object_->Output(out, Precedence(), CYLeft(flags));
861 if (const char *word = property_->Word())
862 out << "::" << word;
863 else
864 out << "::" << '[' << *property_ << ']';
865 }
866
867 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
868 out << "return";
869 if (value_ != NULL)
870 out << ' ' << *value_;
871 out << ';';
872 }
873
874 void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
875 call_->Output(out, CYLeft(flags));
876 out << ' ';
877 proc_->Output(out, CYRight(flags));
878 }
879
880 void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
881 out << '{' << ' ' << '|' << parameters_ << '|' << '\n';
882 ++out.indent_;
883 out << code_;
884 --out.indent_;
885 out << '\t' << '}';
886 }
887
888 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
889 bool first(true);
890 CYForEach (next, this) {
891 bool last(next->next_ == NULL);
892 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
893 first = false;
894 out << '\t';
895 next->Output(out, jacks);
896 out << '\n';
897 }
898 }
899
900 void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) const {
901 if (this == NULL)
902 return out.Terminate();
903
904 _assert(next_ == NULL);
905
906 CYCompactType compact(Compact());
907
908 if (compact >= request)
909 out << ' ';
910 else {
911 out << '\n';
912 ++out.indent_;
913 out << '\t';
914 }
915
916 Output(out, flags);
917
918 if (compact < request)
919 --out.indent_;
920 }
921
922 void CYString::Output(CYOutput &out, CYFlags flags) const {
923 std::ostringstream str;
924 CYStringify(str, value_, size_);
925 out << str.str().c_str();
926 }
927
928 void CYString::PropertyName(CYOutput &out) const {
929 if (const char *word = Word())
930 out << word;
931 else
932 out << *this;
933 }
934
935 static const char *Reserved_[] = {
936 "false", "null", "true",
937
938 "break", "case", "catch", "continue", "default",
939 "delete", "do", "else", "finally", "for", "function",
940 "if", "in", "instanceof", "new", "return", "switch",
941 "this", "throw", "try", "typeof", "var", "void",
942 "while", "with",
943
944 "debugger", "const",
945
946 "class", "enum", "export", "extends", "import", "super",
947
948 "abstract", "boolean", "byte", "char", "double", "final",
949 "float", "goto", "int", "long", "native", "short",
950 "synchronized", "throws", "transient", "volatile",
951
952 "let", "yield",
953
954 NULL
955 };
956
957 const char *CYString::Word() const {
958 if (size_ == 0 || !WordStartRange_[value_[0]])
959 return NULL;
960 for (size_t i(1); i != size_; ++i)
961 if (!WordEndRange_[value_[i]])
962 return NULL;
963 const char *value(Value());
964 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
965 if (strcmp(*reserved, value) == 0)
966 return NULL;
967 return value;
968 }
969
970 void CYStructDefinition::Output(CYOutput &out, CYFlags flags) const {
971 out << "struct" << ' ' << *name_ << *tail_;
972 }
973
974 void CYStructTail::Output(CYOutput &out) const {
975 out << ' ' << '{' << '\n';
976 ++out.indent_;
977 CYForEach (field, fields_) {
978 out << '\t' << *field->typed_;
979 out.Terminate();
980 out << '\n';
981 }
982 --out.indent_;
983 out << '}';
984 }
985
986 void CYSuperAccess::Output(CYOutput &out, CYFlags flags) const {
987 out << "super";
988 if (const char *word = property_->Word())
989 out << '.' << word;
990 else
991 out << '[' << *property_ << ']';
992 }
993
994 void CYSuperCall::Output(CYOutput &out, CYFlags flags) const {
995 out << "super" << '(' << arguments_ << ')';
996 }
997
998 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
999 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{' << '\n';
1000 ++out.indent_;
1001 out << clauses_;
1002 --out.indent_;
1003 out << '\t' << '}';
1004 }
1005
1006 void CYSymbol::Output(CYOutput &out, CYFlags flags) const {
1007 bool protect((flags & CYNoColon) != 0);
1008 if (protect)
1009 out << '(';
1010 out << ':' << name_;
1011 if (protect)
1012 out << ')';
1013 }
1014
1015 void CYThis::Output(CYOutput &out, CYFlags flags) const {
1016 out << "this";
1017 }
1018
1019 namespace cy {
1020 namespace Syntax {
1021
1022 void Throw::Output(CYOutput &out, CYFlags flags) const {
1023 out << "throw";
1024 if (value_ != NULL)
1025 out << ' ' << *value_;
1026 out << ';';
1027 }
1028
1029 void Try::Output(CYOutput &out, CYFlags flags) const {
1030 out << "try" << ' ';
1031 out << '{' << '\n';
1032 ++out.indent_;
1033 out << code_;
1034 --out.indent_;
1035 out << '\t' << '}';
1036 out << catch_ << finally_;
1037 }
1038
1039 } }
1040
1041 void CYTypeCharacter::Output(CYOutput &out) const {
1042 switch (signing_) {
1043 case CYTypeNeutral: break;
1044 case CYTypeSigned: out << "signed" << ' '; break;
1045 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1046 }
1047
1048 out << "char";
1049 }
1050
1051 void CYTypeError::Output(CYOutput &out) const {
1052 out << "@error";
1053 }
1054
1055 void CYTypeIntegral::Output(CYOutput &out) const {
1056 if (signing_ == CYTypeUnsigned)
1057 out << "unsigned" << ' ';
1058 switch (length_) {
1059 case 0: out << "short"; break;
1060 case 1: out << "int"; break;
1061 case 2: out << "long"; break;
1062 case 3: out << "long" << ' ' << "long"; break;
1063 default: _assert(false);
1064 }
1065 }
1066
1067 void CYTypeStruct::Output(CYOutput &out) const {
1068 out << "struct";
1069 if (name_ != NULL)
1070 out << ' ' << *name_;
1071 else
1072 out << *tail_;
1073 }
1074
1075 void CYTypeReference::Output(CYOutput &out) const {
1076 out << "struct" << ' ' << *name_;
1077 }
1078
1079 void CYTypeVariable::Output(CYOutput &out) const {
1080 out << *name_;
1081 }
1082
1083 void CYTypeVoid::Output(CYOutput &out) const {
1084 out << "void";
1085 }
1086
1087 void CYVar::Output(CYOutput &out, CYFlags flags) const {
1088 out << "var" << ' ';
1089 bindings_->Output(out, flags); // XXX: flags
1090 out << ';';
1091 }
1092
1093 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
1094 out << *name_;
1095 }
1096
1097 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
1098 out << "while" << ' ' << '(' << *test_ << ')';
1099 code_->Single(out, CYRight(flags), CYCompactShort);
1100 }
1101
1102 void CYWith::Output(CYOutput &out, CYFlags flags) const {
1103 out << "with" << ' ' << '(' << *scope_ << ')';
1104 code_->Single(out, CYRight(flags), CYCompactShort);
1105 }
1106
1107 void CYWord::Output(CYOutput &out) const {
1108 out << Word();
1109 if (out.options_.verbose_) {
1110 out('@');
1111 char number[32];
1112 sprintf(number, "%p", this);
1113 out(number);
1114 }
1115 }
1116
1117 void CYWord::PropertyName(CYOutput &out) const {
1118 Output(out);
1119 }
1120
1121 const char *CYWord::Word() const {
1122 return word_;
1123 }