]> git.saurik.com Git - cycript.git/blob - Output.cpp
Attach FFI closure deallocation to Functor's pool.
[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 }
682
683 void CYTypePointerTo::Output(CYOutput &out, CYIdentifier *identifier) const {
684 out << '*';
685 next_->Output(out, Precedence(), identifier);
686 }
687
688 void CYTypeVolatile::Output(CYOutput &out, CYIdentifier *identifier) const {
689 out << "volatile";
690 next_->Output(out, Precedence(), identifier);
691 }
692
693 void CYTypeModifier::Output(CYOutput &out, int precedence, CYIdentifier *identifier) const {
694 if (this == NULL) {
695 out << identifier;
696 return;
697 }
698
699 bool protect(precedence > Precedence());
700
701 if (protect)
702 out << '(';
703 Output(out, identifier);
704 if (protect)
705 out << ')';
706 }
707
708 void CYTypedIdentifier::Output(CYOutput &out) const {
709 specifier_->Output(out);
710 modifier_->Output(out, 0, identifier_);
711 }
712
713 void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
714 out << "@encode(" << typed_ << ")";
715 }
716
717 void CYTypedParameter::Output(CYOutput &out) const {
718 out << typed_;
719 if (next_ != NULL)
720 out << ',' << ' ' << next_;
721 }
722
723 void CYLambda::Output(CYOutput &out, CYFlags flags) const {
724 // XXX: this is seriously wrong
725 out << "[](";
726 out << ")->";
727 out << "{";
728 out << "}";
729 }
730
731 void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
732 out << "typedef" << ' ' << *typed_;
733 out.Terminate();
734 }
735
736 void CYTypeExpression::Output(CYOutput &out, CYFlags flags) const {
737 out << '(' << "typedef" << ' ' << *typed_ << ')';
738 }
739
740 void CYLexical::Output(CYOutput &out, CYFlags flags) const {
741 out << "let" << ' ';
742 bindings_->Output(out, flags); // XXX: flags
743 out << ';';
744 }
745
746 void CYModule::Output(CYOutput &out) const {
747 out << part_;
748 if (next_ != NULL)
749 out << '.' << next_;
750 }
751
752 namespace cy {
753 namespace Syntax {
754
755 void New::Output(CYOutput &out, CYFlags flags) const {
756 out << "new" << ' ';
757 CYFlags jacks(CYNoCall | CYCenter(flags));
758 constructor_->Output(out, Precedence(), jacks);
759 if (arguments_ != NULL)
760 out << '(' << *arguments_ << ')';
761 }
762
763 } }
764
765 void CYNull::Output(CYOutput &out, CYFlags flags) const {
766 out << "null";
767 }
768
769 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
770 std::ostringstream str;
771 CYNumerify(str, Value());
772 std::string value(str.str());
773 out << value.c_str();
774 // XXX: this should probably also handle hex conversions and exponents
775 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
776 out << '.';
777 }
778
779 void CYNumber::PropertyName(CYOutput &out) const {
780 Output(out, CYNoFlags);
781 }
782
783 void CYObject::Output(CYOutput &out, CYFlags flags) const {
784 bool protect((flags & CYNoBrace) != 0);
785 if (protect)
786 out << '(';
787 out << '{' << '\n';
788 ++out.indent_;
789 out << properties_;
790 --out.indent_;
791 out << '\t' << '}';
792 if (protect)
793 out << ')';
794 }
795
796 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
797 lhs_->Output(out, Precedence(), CYLeft(flags));
798 out << Operator();
799 }
800
801 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
802 const char *name(Operator());
803 out << name;
804 if (Alphabetic())
805 out << ' ';
806 rhs_->Output(out, Precedence(), CYRight(flags));
807 }
808
809 void CYScript::Output(CYOutput &out) const {
810 out << code_;
811 }
812
813 void CYProperty::Output(CYOutput &out) const {
814 if (next_ != NULL || out.pretty_)
815 out << ',';
816 out << '\n' << next_;
817 }
818
819 void CYPropertyGetter::Output(CYOutput &out) const {
820 out << "get" << ' ';
821 name_->PropertyName(out);
822 CYFunction::Output(out);
823 CYProperty::Output(out);
824 }
825
826 void CYPropertyMethod::Output(CYOutput &out) const {
827 name_->PropertyName(out);
828 CYFunction::Output(out);
829 CYProperty::Output(out);
830 }
831
832 void CYPropertySetter::Output(CYOutput &out) const {
833 out << "set" << ' ';
834 name_->PropertyName(out);
835 CYFunction::Output(out);
836 CYProperty::Output(out);
837 }
838
839 void CYPropertyValue::Output(CYOutput &out) const {
840 out << '\t';
841 name_->PropertyName(out);
842 out << ':' << ' ';
843 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
844 CYProperty::Output(out);
845 }
846
847 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
848 out << Value();
849 }
850
851 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
852 out << "return";
853 if (value_ != NULL)
854 out << ' ' << *value_;
855 out << ';';
856 }
857
858 void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
859 call_->Output(out, CYLeft(flags));
860 out << ' ';
861 proc_->Output(out, CYRight(flags));
862 }
863
864 void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
865 out << '{' << ' ' << '|' << parameters_ << '|' << '\n';
866 ++out.indent_;
867 out << code_;
868 --out.indent_;
869 out << '\t' << '}';
870 }
871
872 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
873 bool first(true);
874 CYForEach (next, this) {
875 bool last(next->next_ == NULL);
876 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
877 first = false;
878 out << '\t';
879 next->Output(out, jacks);
880 out << '\n';
881 }
882 }
883
884 void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) const {
885 if (this == NULL)
886 return out.Terminate();
887
888 _assert(next_ == NULL);
889
890 CYCompactType compact(Compact());
891
892 if (compact >= request)
893 out << ' ';
894 else {
895 out << '\n';
896 ++out.indent_;
897 out << '\t';
898 }
899
900 Output(out, flags);
901
902 if (compact < request)
903 --out.indent_;
904 }
905
906 void CYString::Output(CYOutput &out, CYFlags flags) const {
907 std::ostringstream str;
908 CYStringify(str, value_, size_);
909 out << str.str().c_str();
910 }
911
912 void CYString::PropertyName(CYOutput &out) const {
913 if (const char *word = Word())
914 out << word;
915 else
916 out << *this;
917 }
918
919 static const char *Reserved_[] = {
920 "false", "null", "true",
921
922 "break", "case", "catch", "continue", "default",
923 "delete", "do", "else", "finally", "for", "function",
924 "if", "in", "instanceof", "new", "return", "switch",
925 "this", "throw", "try", "typeof", "var", "void",
926 "while", "with",
927
928 "debugger", "const",
929
930 "class", "enum", "export", "extends", "import", "super",
931
932 "abstract", "boolean", "byte", "char", "double", "final",
933 "float", "goto", "int", "long", "native", "short",
934 "synchronized", "throws", "transient", "volatile",
935
936 "let", "yield",
937
938 NULL
939 };
940
941 const char *CYString::Word() const {
942 if (size_ == 0 || !WordStartRange_[value_[0]])
943 return NULL;
944 for (size_t i(1); i != size_; ++i)
945 if (!WordEndRange_[value_[i]])
946 return NULL;
947 const char *value(Value());
948 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
949 if (strcmp(*reserved, value) == 0)
950 return NULL;
951 return value;
952 }
953
954 void CYStructDefinition::Output(CYOutput &out, CYFlags flags) const {
955 out << "struct" << ' ' << *name_ << *tail_;
956 }
957
958 void CYStructTail::Output(CYOutput &out) const {
959 out << ' ' << '{' << '\n';
960 ++out.indent_;
961 CYForEach (field, fields_) {
962 out << '\t' << *field->typed_;
963 out.Terminate();
964 out << '\n';
965 }
966 --out.indent_;
967 out << '}';
968 }
969
970 void CYSuperAccess::Output(CYOutput &out, CYFlags flags) const {
971 out << "super";
972 if (const char *word = property_->Word())
973 out << '.' << word;
974 else
975 out << '[' << *property_ << ']';
976 }
977
978 void CYSuperCall::Output(CYOutput &out, CYFlags flags) const {
979 out << "super" << '(' << arguments_ << ')';
980 }
981
982 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
983 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{' << '\n';
984 ++out.indent_;
985 out << clauses_;
986 --out.indent_;
987 out << '\t' << '}';
988 }
989
990 void CYThis::Output(CYOutput &out, CYFlags flags) const {
991 out << "this";
992 }
993
994 namespace cy {
995 namespace Syntax {
996
997 void Throw::Output(CYOutput &out, CYFlags flags) const {
998 out << "throw";
999 if (value_ != NULL)
1000 out << ' ' << *value_;
1001 out << ';';
1002 }
1003
1004 void Try::Output(CYOutput &out, CYFlags flags) const {
1005 out << "try" << ' ';
1006 out << '{' << '\n';
1007 ++out.indent_;
1008 out << code_;
1009 --out.indent_;
1010 out << '\t' << '}';
1011 out << catch_ << finally_;
1012 }
1013
1014 } }
1015
1016 void CYTypeCharacter::Output(CYOutput &out) const {
1017 switch (signing_) {
1018 case CYTypeNeutral: break;
1019 case CYTypeSigned: out << "signed" << ' '; break;
1020 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1021 }
1022
1023 out << "char";
1024 }
1025
1026 void CYTypeError::Output(CYOutput &out) const {
1027 out << "@error";
1028 }
1029
1030 void CYTypeIntegral::Output(CYOutput &out) const {
1031 if (signing_ == CYTypeUnsigned)
1032 out << "unsigned" << ' ';
1033 switch (length_) {
1034 case 0: out << "short"; break;
1035 case 1: out << "int"; break;
1036 case 2: out << "long"; break;
1037 case 3: out << "long" << ' ' << "long"; break;
1038 default: _assert(false);
1039 }
1040 }
1041
1042 void CYTypeStruct::Output(CYOutput &out) const {
1043 out << "struct";
1044 if (name_ != NULL)
1045 out << ' ' << *name_;
1046 else
1047 out << *tail_;
1048 }
1049
1050 void CYTypeReference::Output(CYOutput &out) const {
1051 out << "struct" << ' ' << *name_;
1052 }
1053
1054 void CYTypeVariable::Output(CYOutput &out) const {
1055 out << *name_;
1056 }
1057
1058 void CYTypeVoid::Output(CYOutput &out) const {
1059 out << "void";
1060 }
1061
1062 void CYVar::Output(CYOutput &out, CYFlags flags) const {
1063 out << "var" << ' ';
1064 bindings_->Output(out, flags); // XXX: flags
1065 out << ';';
1066 }
1067
1068 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
1069 out << *name_;
1070 }
1071
1072 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
1073 out << "while" << ' ' << '(' << *test_ << ')';
1074 code_->Single(out, CYRight(flags), CYCompactShort);
1075 }
1076
1077 void CYWith::Output(CYOutput &out, CYFlags flags) const {
1078 out << "with" << ' ' << '(' << *scope_ << ')';
1079 code_->Single(out, CYRight(flags), CYCompactShort);
1080 }
1081
1082 void CYWord::Output(CYOutput &out) const {
1083 out << Word();
1084 if (out.options_.verbose_) {
1085 out('@');
1086 char number[32];
1087 sprintf(number, "%p", this);
1088 out(number);
1089 }
1090 }
1091
1092 void CYWord::PropertyName(CYOutput &out) const {
1093 Output(out);
1094 }
1095
1096 const char *CYWord::Word() const {
1097 return word_;
1098 }