]> git.saurik.com Git - cycript.git/blob - Output.cpp
Move x.type() to typeid(x) and implement variadic.
[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_, CYNoFlags);
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 << "case" << ' ' << *value_;
345 else
346 out << "default";
347 out << ':' << '\n';
348 ++out.indent_;
349 out << code_;
350 --out.indent_;
351 out << next_;
352 }
353
354 void CYDebugger::Output(CYOutput &out, CYFlags flags) const {
355 out << "debugger" << ';';
356 }
357
358 void CYBinding::Output(CYOutput &out, CYFlags flags) const {
359 out << *identifier_;
360 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
361 if (initializer_ != NULL) {
362 out << ' ' << '=' << ' ';
363 initializer_->Output(out, CYAssign::Precedence_, CYRight(flags));
364 }
365 }
366
367 void CYBindings::Output(CYOutput &out) const {
368 Output(out, CYNoFlags);
369 }
370
371 void CYBindings::Output(CYOutput &out, CYFlags flags) const {
372 const CYBindings *binding(this);
373 bool first(true);
374
375 for (;;) {
376 CYBindings *next(binding->next_);
377
378 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
379 first = false;
380 binding->binding_->Output(out, jacks);
381
382 if (next == NULL)
383 break;
384
385 out << ',' << ' ';
386 binding = next;
387 }
388 }
389
390 void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
391 object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger);
392 if (const char *word = property_->Word())
393 out << '.' << word;
394 else
395 out << '[' << *property_ << ']';
396 }
397
398 void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
399 out << "do";
400
401 unsigned line(out.position_.line);
402 unsigned indent(out.indent_);
403 code_->Single(out, CYCenter(flags), CYCompactLong);
404
405 if (out.position_.line != line && out.recent_ == indent)
406 out << ' ';
407 else
408 out << '\n' << '\t';
409
410 out << "while" << ' ' << '(' << *test_ << ')';
411 }
412
413 void CYElementSpread::Output(CYOutput &out) const {
414 out << "..." << value_;
415 }
416
417 void CYElementValue::Output(CYOutput &out) const {
418 if (value_ != NULL)
419 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
420 if (next_ != NULL || value_ == NULL) {
421 out << ',';
422 if (next_ != NULL && !next_->Elision())
423 out << ' ';
424 }
425 if (next_ != NULL)
426 next_->Output(out);
427 }
428
429 void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
430 out.Terminate();
431 }
432
433 void CYEval::Output(CYOutput &out, CYFlags flags) const {
434 _assert(false);
435 }
436
437 void CYExpress::Output(CYOutput &out, CYFlags flags) const {
438 expression_->Output(out, flags | CYNoBFC);
439 out << ';';
440 }
441
442 void CYExpression::Output(CYOutput &out) const {
443 Output(out, CYNoFlags);
444 }
445
446 void CYExpression::Output(CYOutput &out, int precedence, CYFlags flags) const {
447 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
448 out << '(' << *this << ')';
449 else
450 Output(out, flags);
451 }
452
453 void CYExternal::Output(CYOutput &out, CYFlags flags) const {
454 out << "extern" << abi_ << typed_;
455 out.Terminate();
456 }
457
458 void CYFatArrow::Output(CYOutput &out, CYFlags flags) const {
459 out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << '{' << code_ << '}';
460 }
461
462 void CYFinally::Output(CYOutput &out) const {
463 out << ' ' << "finally" << ' ';
464 out << '{' << '\n';
465 ++out.indent_;
466 out << code_;
467 --out.indent_;
468 out << '\t' << '}';
469 }
470
471 void CYFor::Output(CYOutput &out, CYFlags flags) const {
472 out << "for" << ' ' << '(';
473 if (initializer_ != NULL)
474 initializer_->Output(out, CYNoIn);
475 out.Terminate();
476 if (test_ != NULL)
477 out << ' ';
478 out << test_;
479 out.Terminate();
480 if (increment_ != NULL)
481 out << ' ';
482 out << increment_;
483 out << ')';
484 code_->Single(out, CYRight(flags), CYCompactShort);
485 }
486
487 void CYForLexical::Output(CYOutput &out, CYFlags flags) const {
488 out << (constant_ ? "const" : "let") << ' ';
489 binding_->Output(out, CYRight(flags));
490 }
491
492 void CYForIn::Output(CYOutput &out, CYFlags flags) const {
493 out << "for" << ' ' << '(';
494 initializer_->Output(out, CYNoIn | CYNoRightHand);
495 out << ' ' << "in" << ' ' << *iterable_ << ')';
496 code_->Single(out, CYRight(flags), CYCompactShort);
497 }
498
499 void CYForInitialized::Output(CYOutput &out, CYFlags flags) const {
500 out << "for" << ' ' << '(' << "var" << ' ';
501 binding_->Output(out, CYNoIn | CYNoRightHand);
502 out << ' ' << "in" << ' ' << *iterable_ << ')';
503 code_->Single(out, CYRight(flags), CYCompactShort);
504 }
505
506 void CYForInComprehension::Output(CYOutput &out) const {
507 out << "for" << ' ' << '(';
508 binding_->Output(out, CYNoIn | CYNoRightHand);
509 out << ' ' << "in" << ' ' << *iterable_ << ')';
510 }
511
512 void CYForOf::Output(CYOutput &out, CYFlags flags) const {
513 out << "for" << ' ' << '(';
514 initializer_->Output(out, CYNoRightHand);
515 out << ' ' << "of" << ' ' << *iterable_ << ')';
516 code_->Single(out, CYRight(flags), CYCompactShort);
517 }
518
519 void CYForOfComprehension::Output(CYOutput &out) const {
520 out << "for" << ' ' << '(';
521 binding_->Output(out, CYNoRightHand);
522 out << ' ' << "of" << ' ' << *iterable_ << ')' << next_;
523 }
524
525 void CYForVariable::Output(CYOutput &out, CYFlags flags) const {
526 out << "var" << ' ';
527 binding_->Output(out, CYRight(flags));
528 }
529
530 void CYFunction::Output(CYOutput &out) const {
531 out << '(' << parameters_ << ')' << ' ';
532 out << '{' << '\n';
533 ++out.indent_;
534 out << code_;
535 --out.indent_;
536 out << '\t' << '}';
537 }
538
539 void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
540 // XXX: one could imagine using + here to save a byte
541 bool protect((flags & CYNoFunction) != 0);
542 if (protect)
543 out << '(';
544 out << "function";
545 if (name_ != NULL)
546 out << ' ' << *name_;
547 CYFunction::Output(out);
548 if (protect)
549 out << ')';
550 }
551
552 void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
553 out << "function" << ' ' << *name_;
554 CYFunction::Output(out);
555 }
556
557 void CYFunctionParameter::Output(CYOutput &out) const {
558 binding_->Output(out, CYNoFlags);
559 if (next_ != NULL)
560 out << ',' << ' ' << *next_;
561 }
562
563 const char *CYIdentifier::Word() const {
564 return next_ == NULL || next_ == this ? CYWord::Word() : next_->Word();
565 }
566
567 void CYIf::Output(CYOutput &out, CYFlags flags) const {
568 bool protect(false);
569 if (false_ == NULL && (flags & CYNoDangle) != 0) {
570 protect = true;
571 out << '{';
572 }
573
574 out << "if" << ' ' << '(' << *test_ << ')';
575
576 CYFlags right(protect ? CYNoFlags : CYRight(flags));
577
578 CYFlags jacks(CYNoDangle);
579 if (false_ == NULL)
580 jacks |= right;
581 else
582 jacks |= protect ? CYNoFlags : CYCenter(flags);
583
584 unsigned line(out.position_.line);
585 unsigned indent(out.indent_);
586 true_->Single(out, jacks, CYCompactShort);
587
588 if (false_ != NULL) {
589 if (out.position_.line != line && out.recent_ == indent)
590 out << ' ';
591 else
592 out << '\n' << '\t';
593
594 out << "else";
595 false_->Single(out, right, CYCompactLong);
596 }
597
598 if (protect)
599 out << '}';
600 }
601
602 void CYIfComprehension::Output(CYOutput &out) const {
603 out << "if" << ' ' << '(' << *test_ << ')' << next_;
604 }
605
606 void CYImport::Output(CYOutput &out, CYFlags flags) const {
607 out << "@import";
608 }
609
610 void CYImportDeclaration::Output(CYOutput &out, CYFlags flags) const {
611 _assert(false);
612 }
613
614 void CYIndirect::Output(CYOutput &out, CYFlags flags) const {
615 out << "*";
616 rhs_->Output(out, Precedence(), CYRight(flags));
617 }
618
619 void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
620 object_->Output(out, Precedence(), CYLeft(flags));
621 if (const char *word = property_->Word())
622 out << "->" << word;
623 else
624 out << "->" << '[' << *property_ << ']';
625 }
626
627 void CYInfix::Output(CYOutput &out, CYFlags flags) const {
628 const char *name(Operator());
629 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
630 if (protect)
631 out << '(';
632 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
633 lhs_->Output(out, Precedence(), left);
634 out << ' ' << name << ' ';
635 CYFlags right(protect ? CYNoFlags : CYRight(flags));
636 rhs_->Output(out, Precedence() - 1, right);
637 if (protect)
638 out << ')';
639 }
640
641 void CYLabel::Output(CYOutput &out, CYFlags flags) const {
642 out << *name_ << ':';
643 statement_->Single(out, CYRight(flags), CYCompactShort);
644 }
645
646 void CYParenthetical::Output(CYOutput &out, CYFlags flags) const {
647 out << '(';
648 expression_->Output(out, CYCompound::Precedence_, CYNoFlags);
649 out << ')';
650 }
651
652 void CYStatement::Output(CYOutput &out) const {
653 Multiple(out);
654 }
655
656 void CYTemplate::Output(CYOutput &out, CYFlags flags) const {
657 _assert(false);
658 }
659
660 void CYTypeArrayOf::Output(CYOutput &out, CYIdentifier *identifier) const {
661 next_->Output(out, Precedence(), identifier);
662 out << '[';
663 out << size_;
664 out << ']';
665 }
666
667 void CYTypeBlockWith::Output(CYOutput &out, CYIdentifier *identifier) const {
668 out << '(' << '^';
669 next_->Output(out, Precedence(), identifier);
670 out << ')' << '(' << parameters_ << ')';
671 }
672
673 void CYTypeConstant::Output(CYOutput &out, CYIdentifier *identifier) const {
674 out << "const" << ' ';
675 next_->Output(out, Precedence(), identifier);
676 }
677
678 void CYTypeFunctionWith::Output(CYOutput &out, CYIdentifier *identifier) const {
679 next_->Output(out, Precedence(), identifier);
680 out << '(' << parameters_;
681 if (variadic_) {
682 if (parameters_ != NULL)
683 out << ',' << ' ';
684 out << "...";
685 }
686 out << ')';
687 }
688
689 void CYTypePointerTo::Output(CYOutput &out, CYIdentifier *identifier) const {
690 out << '*';
691 next_->Output(out, Precedence(), identifier);
692 }
693
694 void CYTypeVolatile::Output(CYOutput &out, CYIdentifier *identifier) const {
695 out << "volatile";
696 next_->Output(out, Precedence(), identifier);
697 }
698
699 void CYTypeModifier::Output(CYOutput &out, int precedence, CYIdentifier *identifier) const {
700 if (this == NULL) {
701 out << identifier;
702 return;
703 }
704
705 bool protect(precedence > Precedence());
706
707 if (protect)
708 out << '(';
709 Output(out, identifier);
710 if (protect)
711 out << ')';
712 }
713
714 void CYTypedIdentifier::Output(CYOutput &out) const {
715 specifier_->Output(out);
716 modifier_->Output(out, 0, identifier_);
717 }
718
719 void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
720 out << "@encode(" << typed_ << ")";
721 }
722
723 void CYTypedParameter::Output(CYOutput &out) const {
724 out << typed_;
725 if (next_ != NULL)
726 out << ',' << ' ' << next_;
727 }
728
729 void CYLambda::Output(CYOutput &out, CYFlags flags) const {
730 // XXX: this is seriously wrong
731 out << "[](";
732 out << ")->";
733 out << "{";
734 out << "}";
735 }
736
737 void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
738 out << "typedef" << ' ' << *typed_;
739 out.Terminate();
740 }
741
742 void CYTypeExpression::Output(CYOutput &out, CYFlags flags) const {
743 out << '(' << "typedef" << ' ' << *typed_ << ')';
744 }
745
746 void CYLexical::Output(CYOutput &out, CYFlags flags) const {
747 out << "let" << ' ';
748 bindings_->Output(out, flags); // XXX: flags
749 out << ';';
750 }
751
752 void CYModule::Output(CYOutput &out) const {
753 out << part_;
754 if (next_ != NULL)
755 out << '.' << next_;
756 }
757
758 namespace cy {
759 namespace Syntax {
760
761 void New::Output(CYOutput &out, CYFlags flags) const {
762 out << "new" << ' ';
763 CYFlags jacks(CYNoCall | CYCenter(flags));
764 constructor_->Output(out, Precedence(), jacks);
765 if (arguments_ != NULL)
766 out << '(' << *arguments_ << ')';
767 }
768
769 } }
770
771 void CYNull::Output(CYOutput &out, CYFlags flags) const {
772 out << "null";
773 }
774
775 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
776 std::ostringstream str;
777 CYNumerify(str, Value());
778 std::string value(str.str());
779 out << value.c_str();
780 // XXX: this should probably also handle hex conversions and exponents
781 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
782 out << '.';
783 }
784
785 void CYNumber::PropertyName(CYOutput &out) const {
786 Output(out, CYNoFlags);
787 }
788
789 void CYObject::Output(CYOutput &out, CYFlags flags) const {
790 bool protect((flags & CYNoBrace) != 0);
791 if (protect)
792 out << '(';
793 out << '{' << '\n';
794 ++out.indent_;
795 out << properties_;
796 --out.indent_;
797 out << '\t' << '}';
798 if (protect)
799 out << ')';
800 }
801
802 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
803 lhs_->Output(out, Precedence(), CYLeft(flags));
804 out << Operator();
805 }
806
807 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
808 const char *name(Operator());
809 out << name;
810 if (Alphabetic())
811 out << ' ';
812 rhs_->Output(out, Precedence(), CYRight(flags));
813 }
814
815 void CYScript::Output(CYOutput &out) const {
816 out << code_;
817 }
818
819 void CYProperty::Output(CYOutput &out) const {
820 if (next_ != NULL || out.pretty_)
821 out << ',';
822 out << '\n' << next_;
823 }
824
825 void CYPropertyGetter::Output(CYOutput &out) const {
826 out << "get" << ' ';
827 name_->PropertyName(out);
828 CYFunction::Output(out);
829 CYProperty::Output(out);
830 }
831
832 void CYPropertyMethod::Output(CYOutput &out) const {
833 name_->PropertyName(out);
834 CYFunction::Output(out);
835 CYProperty::Output(out);
836 }
837
838 void CYPropertySetter::Output(CYOutput &out) const {
839 out << "set" << ' ';
840 name_->PropertyName(out);
841 CYFunction::Output(out);
842 CYProperty::Output(out);
843 }
844
845 void CYPropertyValue::Output(CYOutput &out) const {
846 out << '\t';
847 name_->PropertyName(out);
848 out << ':' << ' ';
849 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
850 CYProperty::Output(out);
851 }
852
853 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
854 out << Value();
855 }
856
857 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
858 out << "return";
859 if (value_ != NULL)
860 out << ' ' << *value_;
861 out << ';';
862 }
863
864 void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
865 call_->Output(out, CYLeft(flags));
866 out << ' ';
867 proc_->Output(out, CYRight(flags));
868 }
869
870 void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
871 out << '{' << ' ' << '|' << parameters_ << '|' << '\n';
872 ++out.indent_;
873 out << code_;
874 --out.indent_;
875 out << '\t' << '}';
876 }
877
878 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
879 bool first(true);
880 CYForEach (next, this) {
881 bool last(next->next_ == NULL);
882 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
883 first = false;
884 out << '\t';
885 next->Output(out, jacks);
886 out << '\n';
887 }
888 }
889
890 void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) const {
891 if (this == NULL)
892 return out.Terminate();
893
894 _assert(next_ == NULL);
895
896 CYCompactType compact(Compact());
897
898 if (compact >= request)
899 out << ' ';
900 else {
901 out << '\n';
902 ++out.indent_;
903 out << '\t';
904 }
905
906 Output(out, flags);
907
908 if (compact < request)
909 --out.indent_;
910 }
911
912 void CYString::Output(CYOutput &out, CYFlags flags) const {
913 std::ostringstream str;
914 CYStringify(str, value_, size_);
915 out << str.str().c_str();
916 }
917
918 void CYString::PropertyName(CYOutput &out) const {
919 if (const char *word = Word())
920 out << word;
921 else
922 out << *this;
923 }
924
925 static const char *Reserved_[] = {
926 "false", "null", "true",
927
928 "break", "case", "catch", "continue", "default",
929 "delete", "do", "else", "finally", "for", "function",
930 "if", "in", "instanceof", "new", "return", "switch",
931 "this", "throw", "try", "typeof", "var", "void",
932 "while", "with",
933
934 "debugger", "const",
935
936 "class", "enum", "export", "extends", "import", "super",
937
938 "abstract", "boolean", "byte", "char", "double", "final",
939 "float", "goto", "int", "long", "native", "short",
940 "synchronized", "throws", "transient", "volatile",
941
942 "let", "yield",
943
944 NULL
945 };
946
947 const char *CYString::Word() const {
948 if (size_ == 0 || !WordStartRange_[value_[0]])
949 return NULL;
950 for (size_t i(1); i != size_; ++i)
951 if (!WordEndRange_[value_[i]])
952 return NULL;
953 const char *value(Value());
954 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
955 if (strcmp(*reserved, value) == 0)
956 return NULL;
957 return value;
958 }
959
960 void CYStructDefinition::Output(CYOutput &out, CYFlags flags) const {
961 out << "struct" << ' ' << *name_ << *tail_;
962 }
963
964 void CYStructTail::Output(CYOutput &out) const {
965 out << ' ' << '{' << '\n';
966 ++out.indent_;
967 CYForEach (field, fields_) {
968 out << '\t' << *field->typed_;
969 out.Terminate();
970 out << '\n';
971 }
972 --out.indent_;
973 out << '}';
974 }
975
976 void CYSuperAccess::Output(CYOutput &out, CYFlags flags) const {
977 out << "super";
978 if (const char *word = property_->Word())
979 out << '.' << word;
980 else
981 out << '[' << *property_ << ']';
982 }
983
984 void CYSuperCall::Output(CYOutput &out, CYFlags flags) const {
985 out << "super" << '(' << arguments_ << ')';
986 }
987
988 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
989 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{' << '\n';
990 ++out.indent_;
991 out << clauses_;
992 --out.indent_;
993 out << '\t' << '}';
994 }
995
996 void CYThis::Output(CYOutput &out, CYFlags flags) const {
997 out << "this";
998 }
999
1000 namespace cy {
1001 namespace Syntax {
1002
1003 void Throw::Output(CYOutput &out, CYFlags flags) const {
1004 out << "throw";
1005 if (value_ != NULL)
1006 out << ' ' << *value_;
1007 out << ';';
1008 }
1009
1010 void Try::Output(CYOutput &out, CYFlags flags) const {
1011 out << "try" << ' ';
1012 out << '{' << '\n';
1013 ++out.indent_;
1014 out << code_;
1015 --out.indent_;
1016 out << '\t' << '}';
1017 out << catch_ << finally_;
1018 }
1019
1020 } }
1021
1022 void CYTypeCharacter::Output(CYOutput &out) const {
1023 switch (signing_) {
1024 case CYTypeNeutral: break;
1025 case CYTypeSigned: out << "signed" << ' '; break;
1026 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1027 }
1028
1029 out << "char";
1030 }
1031
1032 void CYTypeError::Output(CYOutput &out) const {
1033 out << "@error";
1034 }
1035
1036 void CYTypeIntegral::Output(CYOutput &out) const {
1037 if (signing_ == CYTypeUnsigned)
1038 out << "unsigned" << ' ';
1039 switch (length_) {
1040 case 0: out << "short"; break;
1041 case 1: out << "int"; break;
1042 case 2: out << "long"; break;
1043 case 3: out << "long" << ' ' << "long"; break;
1044 default: _assert(false);
1045 }
1046 }
1047
1048 void CYTypeStruct::Output(CYOutput &out) const {
1049 out << "struct";
1050 if (name_ != NULL)
1051 out << ' ' << *name_;
1052 else
1053 out << *tail_;
1054 }
1055
1056 void CYTypeReference::Output(CYOutput &out) const {
1057 out << "struct" << ' ' << *name_;
1058 }
1059
1060 void CYTypeVariable::Output(CYOutput &out) const {
1061 out << *name_;
1062 }
1063
1064 void CYTypeVoid::Output(CYOutput &out) const {
1065 out << "void";
1066 }
1067
1068 void CYVar::Output(CYOutput &out, CYFlags flags) const {
1069 out << "var" << ' ';
1070 bindings_->Output(out, flags); // XXX: flags
1071 out << ';';
1072 }
1073
1074 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
1075 out << *name_;
1076 }
1077
1078 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
1079 out << "while" << ' ' << '(' << *test_ << ')';
1080 code_->Single(out, CYRight(flags), CYCompactShort);
1081 }
1082
1083 void CYWith::Output(CYOutput &out, CYFlags flags) const {
1084 out << "with" << ' ' << '(' << *scope_ << ')';
1085 code_->Single(out, CYRight(flags), CYCompactShort);
1086 }
1087
1088 void CYWord::Output(CYOutput &out) const {
1089 out << Word();
1090 if (out.options_.verbose_) {
1091 out('@');
1092 char number[32];
1093 sprintf(number, "%p", this);
1094 out(number);
1095 }
1096 }
1097
1098 void CYWord::PropertyName(CYOutput &out) const {
1099 Output(out);
1100 }
1101
1102 const char *CYWord::Word() const {
1103 return word_;
1104 }