]> git.saurik.com Git - cycript.git/blame_incremental - Output.cpp
With -p on all platforms, we can't use asprintf().
[cycript.git] / Output.cpp
... / ...
CommitLineData
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
28enum CYStringType {
29 CYStringTypeSingle,
30 CYStringTypeDouble,
31 CYStringTypeTemplate,
32};
33
34void 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
177void 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
191void CYOutput::Terminate() {
192 operator ()(';');
193 mode_ = NoMode;
194}
195
196CYOutput &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
251CYOutput &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
277void 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
291void CYArray::Output(CYOutput &out, CYFlags flags) const {
292 out << '[' << elements_ << ']';
293}
294
295void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
296 out << '[' << *expression_ << ' ' << *comprehensions_ << ']';
297}
298
299void 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
305void CYAttemptMember::Output(CYOutput &out, CYFlags flags) const {
306 object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger);
307 if (const char *word = property_->Word())
308 out << "?." << word;
309 else
310 _assert(false);
311}
312
313void CYBlock::Output(CYOutput &out, CYFlags flags) const {
314 out << '{' << '\n';
315 ++out.indent_;
316 out << code_;
317 --out.indent_;
318 out << '\t' << '}';
319}
320
321void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
322 out << '!' << (Value() ? "0" : "1");
323 if ((flags & CYNoInteger) != 0)
324 out << '.';
325}
326
327void CYBreak::Output(CYOutput &out, CYFlags flags) const {
328 out << "break";
329 if (label_ != NULL)
330 out << ' ' << *label_;
331 out << ';';
332}
333
334void CYCall::Output(CYOutput &out, CYFlags flags) const {
335 bool protect((flags & CYNoCall) != 0);
336 if (protect)
337 out << '(';
338 function_->Output(out, Precedence(), protect ? CYNoFlags : flags);
339 out << '(' << arguments_ << ')';
340 if (protect)
341 out << ')';
342}
343
344namespace cy {
345namespace Syntax {
346
347void Catch::Output(CYOutput &out) const {
348 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ';
349 out << '{' << '\n';
350 ++out.indent_;
351 out << code_;
352 --out.indent_;
353 out << '\t' << '}';
354}
355
356} }
357
358void CYClassExpression::Output(CYOutput &out, CYFlags flags) const {
359 bool protect((flags & CYNoClass) != 0);
360 if (protect)
361 out << '(';
362 out << "class";
363 if (name_ != NULL)
364 out << ' ' << *name_;
365 out << *tail_;;
366 if (protect)
367 out << ')';
368}
369
370void CYClassStatement::Output(CYOutput &out, CYFlags flags) const {
371 out << "class" << ' ' << *name_ << *tail_;
372}
373
374void CYClassTail::Output(CYOutput &out) const {
375 if (extends_ == NULL)
376 out << ' ';
377 else {
378 out << '\n';
379 ++out.indent_;
380 out << "extends" << ' ';
381 extends_->Output(out, CYAssign::Precedence_ - 1, CYNoFlags);
382 out << '\n';
383 --out.indent_;
384 }
385
386 out << '{' << '\n';
387 ++out.indent_;
388
389 --out.indent_;
390 out << '}';
391}
392
393void CYCompound::Output(CYOutput &out, CYFlags flags) const {
394 if (next_ == NULL)
395 expression_->Output(out, flags);
396 else {
397 expression_->Output(out, CYLeft(flags));
398 out << ',' << ' ';
399 next_->Output(out, CYRight(flags));
400 }
401}
402
403void CYComputed::PropertyName(CYOutput &out) const {
404 out << '[';
405 expression_->Output(out, CYAssign::Precedence_, CYNoFlags);
406 out << ']';
407}
408
409void CYCondition::Output(CYOutput &out, CYFlags flags) const {
410 test_->Output(out, Precedence() - 1, CYLeft(flags));
411 out << ' ' << '?' << ' ';
412 if (true_ != NULL)
413 true_->Output(out, CYAssign::Precedence_, CYNoColon);
414 out << ' ' << ':' << ' ';
415 false_->Output(out, CYAssign::Precedence_, CYRight(flags));
416}
417
418void CYContinue::Output(CYOutput &out, CYFlags flags) const {
419 out << "continue";
420 if (label_ != NULL)
421 out << ' ' << *label_;
422 out << ';';
423}
424
425void CYClause::Output(CYOutput &out) const {
426 out << '\t';
427 if (value_ == NULL)
428 out << "default";
429 else {
430 out << "case" << ' ';
431 value_->Output(out, CYNoColon);
432 }
433 out << ':' << '\n';
434 ++out.indent_;
435 out << code_;
436 --out.indent_;
437 out << next_;
438}
439
440void CYDebugger::Output(CYOutput &out, CYFlags flags) const {
441 out << "debugger" << ';';
442}
443
444void CYBinding::Output(CYOutput &out, CYFlags flags) const {
445 out << *identifier_;
446 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
447 if (initializer_ != NULL) {
448 out << ' ' << '=' << ' ';
449 initializer_->Output(out, CYAssign::Precedence_, CYRight(flags));
450 }
451}
452
453void CYBindings::Output(CYOutput &out) const {
454 Output(out, CYNoFlags);
455}
456
457void CYBindings::Output(CYOutput &out, CYFlags flags) const {
458 const CYBindings *binding(this);
459 bool first(true);
460
461 for (;;) {
462 CYBindings *next(binding->next_);
463
464 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
465 first = false;
466 binding->binding_->Output(out, jacks);
467
468 if (next == NULL)
469 break;
470
471 out << ',' << ' ';
472 binding = next;
473 }
474}
475
476void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
477 object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger);
478 if (const char *word = property_->Word())
479 out << '.' << word;
480 else
481 out << '[' << *property_ << ']';
482}
483
484void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
485 out << "do";
486
487 unsigned line(out.position_.line);
488 unsigned indent(out.indent_);
489 code_->Single(out, CYCenter(flags), CYCompactLong);
490
491 if (out.position_.line != line && out.recent_ == indent)
492 out << ' ';
493 else
494 out << '\n' << '\t';
495
496 out << "while" << ' ' << '(' << *test_ << ')';
497}
498
499void CYElementSpread::Output(CYOutput &out) const {
500 out << "..." << value_;
501}
502
503void CYElementValue::Output(CYOutput &out) const {
504 if (value_ != NULL)
505 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
506 if (next_ != NULL || value_ == NULL) {
507 out << ',';
508 if (next_ != NULL && !next_->Elision())
509 out << ' ';
510 }
511 if (next_ != NULL)
512 next_->Output(out);
513}
514
515void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
516 out.Terminate();
517}
518
519void CYEval::Output(CYOutput &out, CYFlags flags) const {
520 _assert(false);
521}
522
523void CYExpress::Output(CYOutput &out, CYFlags flags) const {
524 expression_->Output(out, flags | CYNoBFC);
525 out << ';';
526}
527
528void CYExpression::Output(CYOutput &out) const {
529 Output(out, CYNoFlags);
530}
531
532void CYExpression::Output(CYOutput &out, int precedence, CYFlags flags) const {
533 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
534 out << '(' << *this << ')';
535 else
536 Output(out, flags);
537}
538
539void CYExtend::Output(CYOutput &out, CYFlags flags) const {
540 lhs_->Output(out, CYLeft(flags));
541 out << ' ' << object_;
542}
543
544void CYExternalDefinition::Output(CYOutput &out, CYFlags flags) const {
545 out << "extern" << ' ' << abi_ << ' ';
546 type_->Output(out, name_);
547 out.Terminate();
548}
549
550void CYExternalExpression::Output(CYOutput &out, CYFlags flags) const {
551 out << '(' << "extern" << ' ' << abi_ << ' ';
552 type_->Output(out, name_);
553 out << ')';
554}
555
556void CYFatArrow::Output(CYOutput &out, CYFlags flags) const {
557 out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << '{' << code_ << '}';
558}
559
560void CYFinally::Output(CYOutput &out) const {
561 out << ' ' << "finally" << ' ';
562 out << '{' << '\n';
563 ++out.indent_;
564 out << code_;
565 --out.indent_;
566 out << '\t' << '}';
567}
568
569void CYFor::Output(CYOutput &out, CYFlags flags) const {
570 out << "for" << ' ' << '(';
571 if (initializer_ != NULL)
572 initializer_->Output(out, CYNoIn);
573 out.Terminate();
574 if (test_ != NULL)
575 out << ' ';
576 out << test_;
577 out.Terminate();
578 if (increment_ != NULL)
579 out << ' ';
580 out << increment_;
581 out << ')';
582 code_->Single(out, CYRight(flags), CYCompactShort);
583}
584
585void CYForLexical::Output(CYOutput &out, CYFlags flags) const {
586 out << (constant_ ? "const" : "let") << ' ';
587 binding_->Output(out, CYRight(flags));
588}
589
590void CYForIn::Output(CYOutput &out, CYFlags flags) const {
591 out << "for" << ' ' << '(';
592 initializer_->Output(out, CYNoIn | CYNoRightHand);
593 out << ' ' << "in" << ' ' << *iterable_ << ')';
594 code_->Single(out, CYRight(flags), CYCompactShort);
595}
596
597void CYForInitialized::Output(CYOutput &out, CYFlags flags) const {
598 out << "for" << ' ' << '(' << "var" << ' ';
599 binding_->Output(out, CYNoIn | CYNoRightHand);
600 out << ' ' << "in" << ' ' << *iterable_ << ')';
601 code_->Single(out, CYRight(flags), CYCompactShort);
602}
603
604void CYForInComprehension::Output(CYOutput &out) const {
605 out << "for" << ' ' << '(';
606 binding_->Output(out, CYNoIn | CYNoRightHand);
607 out << ' ' << "in" << ' ' << *iterable_ << ')';
608}
609
610void CYForOf::Output(CYOutput &out, CYFlags flags) const {
611 out << "for" << ' ' << '(';
612 initializer_->Output(out, CYNoRightHand);
613 out << ' ' << "of" << ' ' << *iterable_ << ')';
614 code_->Single(out, CYRight(flags), CYCompactShort);
615}
616
617void CYForOfComprehension::Output(CYOutput &out) const {
618 out << "for" << ' ' << '(';
619 binding_->Output(out, CYNoRightHand);
620 out << ' ' << "of" << ' ' << *iterable_ << ')' << next_;
621}
622
623void CYForVariable::Output(CYOutput &out, CYFlags flags) const {
624 out << "var" << ' ';
625 binding_->Output(out, CYRight(flags));
626}
627
628void CYFunction::Output(CYOutput &out) const {
629 out << '(' << parameters_ << ')' << ' ';
630 out << '{' << '\n';
631 ++out.indent_;
632 out << code_;
633 --out.indent_;
634 out << '\t' << '}';
635}
636
637void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
638 // XXX: one could imagine using + here to save a byte
639 bool protect((flags & CYNoFunction) != 0);
640 if (protect)
641 out << '(';
642 out << "function";
643 if (name_ != NULL)
644 out << ' ' << *name_;
645 CYFunction::Output(out);
646 if (protect)
647 out << ')';
648}
649
650void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
651 out << "function" << ' ' << *name_;
652 CYFunction::Output(out);
653}
654
655void CYFunctionParameter::Output(CYOutput &out) const {
656 binding_->Output(out, CYNoFlags);
657 if (next_ != NULL)
658 out << ',' << ' ' << *next_;
659}
660
661const char *CYIdentifier::Word() const {
662 return next_ == NULL || next_ == this ? CYWord::Word() : next_->Word();
663}
664
665void CYIf::Output(CYOutput &out, CYFlags flags) const {
666 bool protect(false);
667 if (false_ == NULL && (flags & CYNoDangle) != 0) {
668 protect = true;
669 out << '{';
670 }
671
672 out << "if" << ' ' << '(' << *test_ << ')';
673
674 CYFlags right(protect ? CYNoFlags : CYRight(flags));
675
676 CYFlags jacks(CYNoDangle);
677 if (false_ == NULL)
678 jacks |= right;
679 else
680 jacks |= protect ? CYNoFlags : CYCenter(flags);
681
682 unsigned line(out.position_.line);
683 unsigned indent(out.indent_);
684 true_->Single(out, jacks, CYCompactShort);
685
686 if (false_ != NULL) {
687 if (out.position_.line != line && out.recent_ == indent)
688 out << ' ';
689 else
690 out << '\n' << '\t';
691
692 out << "else";
693 false_->Single(out, right, CYCompactLong);
694 }
695
696 if (protect)
697 out << '}';
698}
699
700void CYIfComprehension::Output(CYOutput &out) const {
701 out << "if" << ' ' << '(' << *test_ << ')' << next_;
702}
703
704void CYImport::Output(CYOutput &out, CYFlags flags) const {
705 out << "@import";
706}
707
708void CYImportDeclaration::Output(CYOutput &out, CYFlags flags) const {
709 _assert(false);
710}
711
712void CYIndirect::Output(CYOutput &out, CYFlags flags) const {
713 out << "*";
714 rhs_->Output(out, Precedence(), CYRight(flags));
715}
716
717void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
718 object_->Output(out, Precedence(), CYLeft(flags));
719 if (const char *word = property_->Word())
720 out << "->" << word;
721 else
722 out << "->" << '[' << *property_ << ']';
723}
724
725void CYInfix::Output(CYOutput &out, CYFlags flags) const {
726 const char *name(Operator());
727 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
728 if (protect)
729 out << '(';
730 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
731 lhs_->Output(out, Precedence(), left);
732 out << ' ' << name << ' ';
733 CYFlags right(protect ? CYNoFlags : CYRight(flags));
734 rhs_->Output(out, Precedence() - 1, right);
735 if (protect)
736 out << ')';
737}
738
739void CYLabel::Output(CYOutput &out, CYFlags flags) const {
740 out << *name_ << ':';
741 statement_->Single(out, CYRight(flags), CYCompactShort);
742}
743
744void CYParenthetical::Output(CYOutput &out, CYFlags flags) const {
745 out << '(';
746 expression_->Output(out, CYCompound::Precedence_, CYNoFlags);
747 out << ')';
748}
749
750void CYStatement::Output(CYOutput &out) const {
751 Multiple(out);
752}
753
754void CYTemplate::Output(CYOutput &out, CYFlags flags) const {
755 _assert(false);
756}
757
758void CYTypeArrayOf::Output(CYOutput &out, CYPropertyName *name) const {
759 next_->Output(out, Precedence(), name, false);
760 out << '[';
761 out << size_;
762 out << ']';
763}
764
765void CYTypeBlockWith::Output(CYOutput &out, CYPropertyName *name) const {
766 out << '(' << '^';
767 next_->Output(out, Precedence(), name, false);
768 out << ')' << '(' << parameters_ << ')';
769}
770
771void CYTypeConstant::Output(CYOutput &out, CYPropertyName *name) const {
772 out << "const";
773 next_->Output(out, Precedence(), name, false);
774}
775
776void CYTypeFunctionWith::Output(CYOutput &out, CYPropertyName *name) const {
777 next_->Output(out, Precedence(), name, false);
778 out << '(' << parameters_;
779 if (variadic_) {
780 if (parameters_ != NULL)
781 out << ',' << ' ';
782 out << "...";
783 }
784 out << ')';
785}
786
787void CYTypePointerTo::Output(CYOutput &out, CYPropertyName *name) const {
788 out << '*';
789 next_->Output(out, Precedence(), name, false);
790}
791
792void CYTypeVolatile::Output(CYOutput &out, CYPropertyName *name) const {
793 out << "volatile";
794 next_->Output(out, Precedence(), name, true);
795}
796
797void CYTypeModifier::Output(CYOutput &out, int precedence, CYPropertyName *name, bool space) const {
798 if (this == NULL && name == NULL)
799 return;
800 else if (space)
801 out << ' ';
802
803 if (this == NULL) {
804 name->PropertyName(out);
805 return;
806 }
807
808 bool protect(precedence > Precedence());
809
810 if (protect)
811 out << '(';
812 Output(out, name);
813 if (protect)
814 out << ')';
815}
816
817void CYType::Output(CYOutput &out, CYPropertyName *name) const {
818 out << *specifier_;
819 modifier_->Output(out, 0, name, true);
820}
821
822void CYType::Output(CYOutput &out) const {
823 Output(out, NULL);
824}
825
826void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
827 out << "@encode(" << typed_ << ")";
828}
829
830void CYTypedParameter::Output(CYOutput &out) const {
831 type_->Output(out, name_);
832 if (next_ != NULL)
833 out << ',' << ' ' << next_;
834}
835
836void CYLambda::Output(CYOutput &out, CYFlags flags) const {
837 // XXX: this is seriously wrong
838 out << "[](";
839 out << ")->";
840 out << "{";
841 out << "}";
842}
843
844void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
845 out << "typedef" << ' ';
846 type_->Output(out, name_);
847 out.Terminate();
848}
849
850void CYTypeExpression::Output(CYOutput &out, CYFlags flags) const {
851 out << '(' << "typedef" << ' ' << *typed_ << ')';
852}
853
854void CYLexical::Output(CYOutput &out, CYFlags flags) const {
855 out << "let" << ' ';
856 bindings_->Output(out, flags); // XXX: flags
857 out << ';';
858}
859
860void CYModule::Output(CYOutput &out) const {
861 out << part_;
862 if (next_ != NULL)
863 out << '.' << next_;
864}
865
866namespace cy {
867namespace Syntax {
868
869void New::Output(CYOutput &out, CYFlags flags) const {
870 out << "new" << ' ';
871 CYFlags jacks(CYNoCall | CYCenter(flags));
872 constructor_->Output(out, Precedence(), jacks);
873 if (arguments_ != NULL)
874 out << '(' << *arguments_ << ')';
875}
876
877} }
878
879void CYNull::Output(CYOutput &out, CYFlags flags) const {
880 out << "null";
881}
882
883void CYNumber::Output(CYOutput &out, CYFlags flags) const {
884 std::ostringstream str;
885 CYNumerify(str, Value());
886 std::string value(str.str());
887 out << value.c_str();
888 // XXX: this should probably also handle hex conversions and exponents
889 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
890 out << '.';
891}
892
893void CYNumber::PropertyName(CYOutput &out) const {
894 Output(out, CYNoFlags);
895}
896
897void CYObject::Output(CYOutput &out, CYFlags flags) const {
898 bool protect((flags & CYNoBrace) != 0);
899 if (protect)
900 out << '(';
901 out << '{' << '\n';
902 ++out.indent_;
903 out << properties_;
904 --out.indent_;
905 out << '\t' << '}';
906 if (protect)
907 out << ')';
908}
909
910void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
911 lhs_->Output(out, Precedence(), CYLeft(flags));
912 out << Operator();
913}
914
915void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
916 const char *name(Operator());
917 out << name;
918 if (Alphabetic())
919 out << ' ';
920 rhs_->Output(out, Precedence(), CYRight(flags));
921}
922
923void CYScript::Output(CYOutput &out) const {
924 out << code_;
925}
926
927void CYProperty::Output(CYOutput &out) const {
928 if (next_ != NULL || out.pretty_)
929 out << ',';
930 out << '\n' << next_;
931}
932
933void CYPropertyGetter::Output(CYOutput &out) const {
934 out << "get" << ' ';
935 name_->PropertyName(out);
936 CYFunction::Output(out);
937 CYProperty::Output(out);
938}
939
940void CYPropertyMethod::Output(CYOutput &out) const {
941 name_->PropertyName(out);
942 CYFunction::Output(out);
943 CYProperty::Output(out);
944}
945
946void CYPropertySetter::Output(CYOutput &out) const {
947 out << "set" << ' ';
948 name_->PropertyName(out);
949 CYFunction::Output(out);
950 CYProperty::Output(out);
951}
952
953void CYPropertyValue::Output(CYOutput &out) const {
954 out << '\t';
955 name_->PropertyName(out);
956 out << ':' << ' ';
957 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
958 CYProperty::Output(out);
959}
960
961void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
962 out << Value();
963}
964
965void CYResolveMember::Output(CYOutput &out, CYFlags flags) const {
966 object_->Output(out, Precedence(), CYLeft(flags));
967 if (const char *word = property_->Word())
968 out << "::" << word;
969 else
970 out << "::" << '[' << *property_ << ']';
971}
972
973void CYReturn::Output(CYOutput &out, CYFlags flags) const {
974 out << "return";
975 if (value_ != NULL)
976 out << ' ' << *value_;
977 out << ';';
978}
979
980void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
981 lhs_->Output(out, CYLeft(flags));
982 out << ' ';
983 proc_->Output(out, CYRight(flags));
984}
985
986void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
987 out << '{' << ' ' << '|' << parameters_ << '|' << '\n';
988 ++out.indent_;
989 out << code_;
990 --out.indent_;
991 out << '\t' << '}';
992}
993
994void CYSubscriptMember::Output(CYOutput &out, CYFlags flags) const {
995 object_->Output(out, Precedence(), CYLeft(flags));
996 out << "." << '[' << *property_ << ']';
997}
998
999void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
1000 bool first(true);
1001 CYForEach (next, this) {
1002 bool last(next->next_ == NULL);
1003 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
1004 first = false;
1005 out << '\t';
1006 next->Output(out, jacks);
1007 out << '\n';
1008 }
1009}
1010
1011void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) const {
1012 if (this == NULL)
1013 return out.Terminate();
1014
1015 _assert(next_ == NULL);
1016
1017 CYCompactType compact(Compact());
1018
1019 if (compact >= request)
1020 out << ' ';
1021 else {
1022 out << '\n';
1023 ++out.indent_;
1024 out << '\t';
1025 }
1026
1027 Output(out, flags);
1028
1029 if (compact < request)
1030 --out.indent_;
1031}
1032
1033void CYString::Output(CYOutput &out, CYFlags flags) const {
1034 std::ostringstream str;
1035 CYStringify(str, value_, size_, CYStringifyModeLegacy);
1036 out << str.str().c_str();
1037}
1038
1039void CYString::PropertyName(CYOutput &out) const {
1040 if (const char *word = Word())
1041 out << word;
1042 else
1043 out << *this;
1044}
1045
1046static const char *Reserved_[] = {
1047 "false", "null", "true",
1048
1049 "break", "case", "catch", "continue", "default",
1050 "delete", "do", "else", "finally", "for", "function",
1051 "if", "in", "instanceof", "new", "return", "switch",
1052 "this", "throw", "try", "typeof", "var", "void",
1053 "while", "with",
1054
1055 "debugger", "const",
1056
1057 "class", "enum", "export", "extends", "import", "super",
1058
1059 "abstract", "boolean", "byte", "char", "double", "final",
1060 "float", "goto", "int", "long", "native", "short",
1061 "synchronized", "throws", "transient", "volatile",
1062
1063 "let", "yield",
1064
1065 NULL
1066};
1067
1068const char *CYString::Word() const {
1069 if (size_ == 0 || !WordStartRange_[value_[0]])
1070 return NULL;
1071 for (size_t i(1); i != size_; ++i)
1072 if (!WordEndRange_[value_[i]])
1073 return NULL;
1074 const char *value(Value());
1075 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
1076 if (strcmp(*reserved, value) == 0)
1077 return NULL;
1078 return value;
1079}
1080
1081void CYStructDefinition::Output(CYOutput &out, CYFlags flags) const {
1082 out << "struct" << ' ' << *name_ << *tail_;
1083}
1084
1085void CYStructTail::Output(CYOutput &out) const {
1086 out << ' ' << '{' << '\n';
1087 ++out.indent_;
1088 CYForEach (field, fields_) {
1089 out << '\t';
1090 field->type_->Output(out, field->name_);
1091 out.Terminate();
1092 out << '\n';
1093 }
1094 --out.indent_;
1095 out << '\t' << '}';
1096}
1097
1098void CYSuperAccess::Output(CYOutput &out, CYFlags flags) const {
1099 out << "super";
1100 if (const char *word = property_->Word())
1101 out << '.' << word;
1102 else
1103 out << '[' << *property_ << ']';
1104}
1105
1106void CYSuperCall::Output(CYOutput &out, CYFlags flags) const {
1107 out << "super" << '(' << arguments_ << ')';
1108}
1109
1110void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
1111 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{' << '\n';
1112 ++out.indent_;
1113 out << clauses_;
1114 --out.indent_;
1115 out << '\t' << '}';
1116}
1117
1118void CYSymbol::Output(CYOutput &out, CYFlags flags) const {
1119 bool protect((flags & CYNoColon) != 0);
1120 if (protect)
1121 out << '(';
1122 out << ':' << name_;
1123 if (protect)
1124 out << ')';
1125}
1126
1127void CYThis::Output(CYOutput &out, CYFlags flags) const {
1128 out << "this";
1129}
1130
1131namespace cy {
1132namespace Syntax {
1133
1134void Throw::Output(CYOutput &out, CYFlags flags) const {
1135 out << "throw";
1136 if (value_ != NULL)
1137 out << ' ' << *value_;
1138 out << ';';
1139}
1140
1141void Try::Output(CYOutput &out, CYFlags flags) const {
1142 out << "try" << ' ';
1143 out << '{' << '\n';
1144 ++out.indent_;
1145 out << code_;
1146 --out.indent_;
1147 out << '\t' << '}';
1148 out << catch_ << finally_;
1149}
1150
1151} }
1152
1153void CYTypeCharacter::Output(CYOutput &out) const {
1154 switch (signing_) {
1155 case CYTypeNeutral: break;
1156 case CYTypeSigned: out << "signed" << ' '; break;
1157 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1158 }
1159
1160 out << "char";
1161}
1162
1163void CYTypeEnum::Output(CYOutput &out) const {
1164 out << "enum" << ' ';
1165 if (name_ != NULL)
1166 out << *name_;
1167 else {
1168 if (specifier_ != NULL)
1169 out << ':' << ' ' << *specifier_ << ' ';
1170
1171 out << '{' << '\n';
1172 ++out.indent_;
1173 bool comma(false);
1174
1175 CYForEach (constant, constants_) {
1176 if (comma)
1177 out << ',' << '\n';
1178 else
1179 comma = true;
1180 out << '\t' << constant->name_;
1181 out << ' ' << '=' << ' ' << constant->value_;
1182 }
1183
1184 if (out.pretty_)
1185 out << ',';
1186 out << '\n';
1187 --out.indent_;
1188 out << '\t' << '}';
1189 }
1190}
1191
1192void CYTypeError::Output(CYOutput &out) const {
1193 out << "@error";
1194}
1195
1196void CYTypeFloating::Output(CYOutput &out) const {
1197 switch (length_) {
1198 case 0: out << "float"; break;
1199 case 1: out << "double"; break;
1200 case 2: out << "long" << ' ' << "double"; break;
1201 default: _assert(false);
1202 }
1203}
1204
1205void CYTypeInt128::Output(CYOutput &out) const {
1206 switch (signing_) {
1207 case CYTypeNeutral: break;
1208 case CYTypeSigned: out << "signed" << ' '; break;
1209 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1210 }
1211
1212 out << "__int128";
1213}
1214
1215void CYTypeIntegral::Output(CYOutput &out) const {
1216 if (signing_ == CYTypeUnsigned)
1217 out << "unsigned" << ' ';
1218 switch (length_) {
1219 case 0: out << "short"; break;
1220 case 1: out << "int"; break;
1221 case 2: out << "long"; break;
1222 case 3: out << "long" << ' ' << "long"; break;
1223 default: _assert(false);
1224 }
1225}
1226
1227void CYTypeStruct::Output(CYOutput &out) const {
1228 out << "struct";
1229 if (name_ != NULL)
1230 out << ' ' << *name_;
1231 else
1232 out << *tail_;
1233}
1234
1235void CYTypeReference::Output(CYOutput &out) const {
1236 switch (kind_) {
1237 case CYTypeReferenceStruct: out << "struct"; break;
1238 case CYTypeReferenceEnum: out << "enum"; break;
1239 default: _assert(false);
1240 }
1241
1242 out << ' ' << *name_;
1243}
1244
1245void CYTypeVariable::Output(CYOutput &out) const {
1246 out << *name_;
1247}
1248
1249void CYTypeVoid::Output(CYOutput &out) const {
1250 out << "void";
1251}
1252
1253void CYVar::Output(CYOutput &out, CYFlags flags) const {
1254 out << "var" << ' ';
1255 bindings_->Output(out, flags); // XXX: flags
1256 out << ';';
1257}
1258
1259void CYVariable::Output(CYOutput &out, CYFlags flags) const {
1260 out << *name_;
1261}
1262
1263void CYWhile::Output(CYOutput &out, CYFlags flags) const {
1264 out << "while" << ' ' << '(' << *test_ << ')';
1265 code_->Single(out, CYRight(flags), CYCompactShort);
1266}
1267
1268void CYWith::Output(CYOutput &out, CYFlags flags) const {
1269 out << "with" << ' ' << '(' << *scope_ << ')';
1270 code_->Single(out, CYRight(flags), CYCompactShort);
1271}
1272
1273void CYWord::Output(CYOutput &out) const {
1274 out << Word();
1275 if (out.options_.verbose_) {
1276 out('@');
1277 char number[32];
1278 sprintf(number, "%p", this);
1279 out(number);
1280 }
1281}
1282
1283void CYWord::PropertyName(CYOutput &out) const {
1284 Output(out);
1285}
1286
1287const char *CYWord::Word() const {
1288 return word_;
1289}