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