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