]> git.saurik.com Git - cycript.git/blob - Output.cpp
Port modules to typedef/extern instead of @encode.
[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 void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c) {
29 bool single;
30 if (c)
31 single = false;
32 else {
33 unsigned quot(0), apos(0);
34 for (const char *value(data), *end(data + size); value != end; ++value)
35 if (*value == '"')
36 ++quot;
37 else if (*value == '\'')
38 ++apos;
39
40 single = quot > apos;
41 }
42
43 str << (single ? '\'' : '"');
44
45 for (const char *value(data), *end(data + size); value != end; ++value)
46 switch (uint8_t next = *value) {
47 case '\\': str << "\\\\"; break;
48 case '\b': str << "\\b"; break;
49 case '\f': str << "\\f"; break;
50 case '\n': str << "\\n"; break;
51 case '\r': str << "\\r"; break;
52 case '\t': str << "\\t"; break;
53 case '\v': str << "\\v"; break;
54
55 case '"':
56 if (!single)
57 str << "\\\"";
58 else goto simple;
59 break;
60
61 case '\'':
62 if (single)
63 str << "\\'";
64 else goto simple;
65 break;
66
67 case '\0':
68 if (value[1] >= '0' && value[1] <= '9')
69 str << "\\x00";
70 else
71 str << "\\0";
72 break;
73
74 default:
75 if (next >= 0x20 && next < 0x7f) simple:
76 str << *value;
77 else {
78 unsigned levels(1);
79 if ((next & 0x80) != 0)
80 while ((next & 0x80 >> ++levels) != 0);
81
82 unsigned point(next & 0xff >> levels);
83 while (--levels != 0)
84 point = point << 6 | uint8_t(*++value) & 0x3f;
85
86 if (point < 0x100)
87 str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << point;
88 else if (point < 0x10000)
89 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << point;
90 else {
91 point -= 0x10000;
92 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xd800 | point >> 0x0a);
93 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xdc00 | point & 0x3ff);
94 }
95 }
96 }
97
98 str << (single ? '\'' : '"');
99 }
100
101 void CYNumerify(std::ostringstream &str, double value) {
102 if (std::isinf(value)) {
103 if (value < 0)
104 str << '-';
105 str << "Infinity";
106 return;
107 }
108
109 char string[32];
110 // XXX: I want this to print 1e3 rather than 1000
111 sprintf(string, "%.17g", value);
112 str << string;
113 }
114
115 void CYOutput::Terminate() {
116 operator ()(';');
117 mode_ = NoMode;
118 }
119
120 CYOutput &CYOutput::operator <<(char rhs) {
121 if (rhs == ' ' || rhs == '\n')
122 if (pretty_)
123 operator ()(rhs);
124 else goto done;
125 else if (rhs == '\t')
126 if (pretty_)
127 for (unsigned i(0); i != indent_; ++i)
128 operator ()(" ", 4);
129 else goto done;
130 else if (rhs == '\r') {
131 if (right_) {
132 operator ()('\n');
133 right_ = false;
134 } goto done;
135 } else goto work;
136
137 right_ = true;
138 mode_ = NoMode;
139 goto done;
140
141 work:
142 if (mode_ == Terminated && rhs != '}') {
143 right_ = true;
144 operator ()(';');
145 }
146
147 if (rhs == ';') {
148 if (pretty_)
149 goto none;
150 else {
151 mode_ = Terminated;
152 goto done;
153 }
154 } else if (rhs == '+') {
155 if (mode_ == NoPlus)
156 operator ()(' ');
157 mode_ = NoPlus;
158 } else if (rhs == '-') {
159 if (mode_ == NoHyphen)
160 operator ()(' ');
161 mode_ = NoHyphen;
162 } else if (WordEndRange_[rhs]) {
163 if (mode_ == NoLetter)
164 operator ()(' ');
165 mode_ = NoLetter;
166 } else none:
167 mode_ = NoMode;
168
169 right_ = true;
170 operator ()(rhs);
171 done:
172 return *this;
173 }
174
175 CYOutput &CYOutput::operator <<(const char *rhs) {
176 size_t size(strlen(rhs));
177
178 if (size == 1)
179 return *this << *rhs;
180
181 if (mode_ == Terminated)
182 operator ()(';');
183 else if (
184 mode_ == NoPlus && *rhs == '+' ||
185 mode_ == NoHyphen && *rhs == '-' ||
186 mode_ == NoLetter && WordEndRange_[*rhs]
187 )
188 operator ()(' ');
189
190 char last(rhs[size - 1]);
191 if (WordEndRange_[last] || last == '/')
192 mode_ = NoLetter;
193 else
194 mode_ = NoMode;
195
196 right_ = true;
197 operator ()(rhs, size);
198 return *this;
199 }
200
201 void CYArgument::Output(CYOutput &out) const {
202 if (name_ != NULL) {
203 out << *name_;
204 if (value_ != NULL)
205 out << ':' << ' ';
206 }
207 if (value_ != NULL)
208 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
209 if (next_ != NULL) {
210 out << ',';
211 out << ' ' << *next_;
212 }
213 }
214
215 void CYArray::Output(CYOutput &out, CYFlags flags) const {
216 out << '[' << elements_ << ']';
217 }
218
219 void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
220 out << '[' << *expression_ << ' ' << *comprehensions_ << ']';
221 }
222
223 void CYAssignment::Output(CYOutput &out, CYFlags flags) const {
224 lhs_->Output(out, Precedence() - 1, CYLeft(flags) | CYNoRightHand);
225 out << ' ' << Operator() << ' ';
226 rhs_->Output(out, Precedence(), CYRight(flags));
227 }
228
229 void CYBlock::Output(CYOutput &out, CYFlags flags) const {
230 out << '{' << '\n';
231 ++out.indent_;
232 out << code_;
233 --out.indent_;
234 out << '\t' << '}';
235 }
236
237 void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
238 out << '!' << (Value() ? "0" : "1");
239 if ((flags & CYNoInteger) != 0)
240 out << '.';
241 }
242
243 void CYBreak::Output(CYOutput &out, CYFlags flags) const {
244 out << "break";
245 if (label_ != NULL)
246 out << ' ' << *label_;
247 out << ';';
248 }
249
250 void CYCall::Output(CYOutput &out, CYFlags flags) const {
251 bool protect((flags & CYNoCall) != 0);
252 if (protect)
253 out << '(';
254 function_->Output(out, Precedence(), protect ? CYNoFlags : flags);
255 out << '(' << arguments_ << ')';
256 if (protect)
257 out << ')';
258 }
259
260 namespace cy {
261 namespace Syntax {
262
263 void Catch::Output(CYOutput &out) const {
264 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ';
265 out << '{' << '\n';
266 ++out.indent_;
267 out << code_;
268 --out.indent_;
269 out << '\t' << '}';
270 }
271
272 } }
273
274 void CYClassExpression::Output(CYOutput &out, CYFlags flags) const {
275 bool protect((flags & CYNoClass) != 0);
276 if (protect)
277 out << '(';
278 out << "class";
279 if (name_ != NULL)
280 out << ' ' << *name_;
281 out << *tail_;;
282 if (protect)
283 out << ')';
284 }
285
286 void CYClassStatement::Output(CYOutput &out, CYFlags flags) const {
287 out << "class" << ' ' << *name_ << *tail_;
288 }
289
290 void CYClassTail::Output(CYOutput &out) const {
291 if (extends_ == NULL)
292 out << ' ';
293 else {
294 out << '\n';
295 ++out.indent_;
296 out << "extends" << ' ';
297 extends_->Output(out, CYAssign::Precedence_ - 1, CYNoFlags);
298 out << '\n';
299 --out.indent_;
300 }
301
302 out << '{' << '\n';
303 ++out.indent_;
304
305 --out.indent_;
306 out << '}';
307 }
308
309 void CYCompound::Output(CYOutput &out, CYFlags flags) const {
310 if (next_ == NULL)
311 expression_->Output(out, flags);
312 else {
313 expression_->Output(out, CYLeft(flags));
314 out << ',' << ' ';
315 next_->Output(out, CYRight(flags));
316 }
317 }
318
319 void CYComputed::PropertyName(CYOutput &out) const {
320 out << '[';
321 expression_->Output(out, CYAssign::Precedence_, CYNoFlags);
322 out << ']';
323 }
324
325 void CYCondition::Output(CYOutput &out, CYFlags flags) const {
326 test_->Output(out, Precedence() - 1, CYLeft(flags));
327 out << ' ' << '?' << ' ';
328 if (true_ != NULL)
329 true_->Output(out, CYAssign::Precedence_, CYNoColon);
330 out << ' ' << ':' << ' ';
331 false_->Output(out, CYAssign::Precedence_, CYRight(flags));
332 }
333
334 void CYContinue::Output(CYOutput &out, CYFlags flags) const {
335 out << "continue";
336 if (label_ != NULL)
337 out << ' ' << *label_;
338 out << ';';
339 }
340
341 void CYClause::Output(CYOutput &out) const {
342 out << '\t';
343 if (value_ == NULL)
344 out << "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
356 void CYDebugger::Output(CYOutput &out, CYFlags flags) const {
357 out << "debugger" << ';';
358 }
359
360 void 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
369 void CYBindings::Output(CYOutput &out) const {
370 Output(out, CYNoFlags);
371 }
372
373 void 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
392 void 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
400 void 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
415 void CYElementSpread::Output(CYOutput &out) const {
416 out << "..." << value_;
417 }
418
419 void 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
431 void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
432 out.Terminate();
433 }
434
435 void CYEval::Output(CYOutput &out, CYFlags flags) const {
436 _assert(false);
437 }
438
439 void CYExpress::Output(CYOutput &out, CYFlags flags) const {
440 expression_->Output(out, flags | CYNoBFC);
441 out << ';';
442 }
443
444 void CYExpression::Output(CYOutput &out) const {
445 Output(out, CYNoFlags);
446 }
447
448 void 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
455 void CYExtend::Output(CYOutput &out, CYFlags flags) const {
456 lhs_->Output(out, CYLeft(flags));
457 out << ' ' << object_;
458 }
459
460 void CYExternalDefinition::Output(CYOutput &out, CYFlags flags) const {
461 out << "extern" << ' ' << abi_ << ' ' << typed_;
462 out.Terminate();
463 }
464
465 void CYExternalExpression::Output(CYOutput &out, CYFlags flags) const {
466 out << '(' << "extern" << ' ' << abi_ << ' ' << typed_ << ')';
467 }
468
469 void CYFatArrow::Output(CYOutput &out, CYFlags flags) const {
470 out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << '{' << code_ << '}';
471 }
472
473 void 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
482 void 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
498 void CYForLexical::Output(CYOutput &out, CYFlags flags) const {
499 out << (constant_ ? "const" : "let") << ' ';
500 binding_->Output(out, CYRight(flags));
501 }
502
503 void 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
510 void 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
517 void CYForInComprehension::Output(CYOutput &out) const {
518 out << "for" << ' ' << '(';
519 binding_->Output(out, CYNoIn | CYNoRightHand);
520 out << ' ' << "in" << ' ' << *iterable_ << ')';
521 }
522
523 void 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
530 void CYForOfComprehension::Output(CYOutput &out) const {
531 out << "for" << ' ' << '(';
532 binding_->Output(out, CYNoRightHand);
533 out << ' ' << "of" << ' ' << *iterable_ << ')' << next_;
534 }
535
536 void CYForVariable::Output(CYOutput &out, CYFlags flags) const {
537 out << "var" << ' ';
538 binding_->Output(out, CYRight(flags));
539 }
540
541 void 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
550 void 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
563 void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
564 out << "function" << ' ' << *name_;
565 CYFunction::Output(out);
566 }
567
568 void CYFunctionParameter::Output(CYOutput &out) const {
569 binding_->Output(out, CYNoFlags);
570 if (next_ != NULL)
571 out << ',' << ' ' << *next_;
572 }
573
574 const char *CYIdentifier::Word() const {
575 return next_ == NULL || next_ == this ? CYWord::Word() : next_->Word();
576 }
577
578 void 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
613 void CYIfComprehension::Output(CYOutput &out) const {
614 out << "if" << ' ' << '(' << *test_ << ')' << next_;
615 }
616
617 void CYImport::Output(CYOutput &out, CYFlags flags) const {
618 out << "@import";
619 }
620
621 void CYImportDeclaration::Output(CYOutput &out, CYFlags flags) const {
622 _assert(false);
623 }
624
625 void CYIndirect::Output(CYOutput &out, CYFlags flags) const {
626 out << "*";
627 rhs_->Output(out, Precedence(), CYRight(flags));
628 }
629
630 void 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
638 void 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
652 void CYLabel::Output(CYOutput &out, CYFlags flags) const {
653 out << *name_ << ':';
654 statement_->Single(out, CYRight(flags), CYCompactShort);
655 }
656
657 void CYParenthetical::Output(CYOutput &out, CYFlags flags) const {
658 out << '(';
659 expression_->Output(out, CYCompound::Precedence_, CYNoFlags);
660 out << ')';
661 }
662
663 void CYStatement::Output(CYOutput &out) const {
664 Multiple(out);
665 }
666
667 void CYTemplate::Output(CYOutput &out, CYFlags flags) const {
668 _assert(false);
669 }
670
671 void CYTypeArrayOf::Output(CYOutput &out, CYIdentifier *identifier) const {
672 next_->Output(out, Precedence(), identifier, false);
673 out << '[';
674 out << size_;
675 out << ']';
676 }
677
678 void CYTypeBlockWith::Output(CYOutput &out, CYIdentifier *identifier) const {
679 out << '(' << '^';
680 next_->Output(out, Precedence(), identifier, false);
681 out << ')' << '(' << parameters_ << ')';
682 }
683
684 void CYTypeConstant::Output(CYOutput &out, CYIdentifier *identifier) const {
685 out << "const";
686 next_->Output(out, Precedence(), identifier, false);
687 }
688
689 void 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
700 void CYTypePointerTo::Output(CYOutput &out, CYIdentifier *identifier) const {
701 out << '*';
702 next_->Output(out, Precedence(), identifier, false);
703 }
704
705 void CYTypeVolatile::Output(CYOutput &out, CYIdentifier *identifier) const {
706 out << "volatile";
707 next_->Output(out, Precedence(), identifier, true);
708 }
709
710 void 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
730 void CYTypedIdentifier::Output(CYOutput &out) const {
731 out << *specifier_;
732 modifier_->Output(out, 0, identifier_, true);
733 }
734
735 void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
736 out << "@encode(" << typed_ << ")";
737 }
738
739 void CYTypedParameter::Output(CYOutput &out) const {
740 out << typed_;
741 if (next_ != NULL)
742 out << ',' << ' ' << next_;
743 }
744
745 void CYLambda::Output(CYOutput &out, CYFlags flags) const {
746 // XXX: this is seriously wrong
747 out << "[](";
748 out << ")->";
749 out << "{";
750 out << "}";
751 }
752
753 void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
754 out << "typedef" << ' ' << *typed_;
755 out.Terminate();
756 }
757
758 void CYTypeExpression::Output(CYOutput &out, CYFlags flags) const {
759 out << '(' << "typedef" << ' ' << *typed_ << ')';
760 }
761
762 void CYLexical::Output(CYOutput &out, CYFlags flags) const {
763 out << "let" << ' ';
764 bindings_->Output(out, flags); // XXX: flags
765 out << ';';
766 }
767
768 void CYModule::Output(CYOutput &out) const {
769 out << part_;
770 if (next_ != NULL)
771 out << '.' << next_;
772 }
773
774 namespace cy {
775 namespace Syntax {
776
777 void 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
787 void CYNull::Output(CYOutput &out, CYFlags flags) const {
788 out << "null";
789 }
790
791 void 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
801 void CYNumber::PropertyName(CYOutput &out) const {
802 Output(out, CYNoFlags);
803 }
804
805 void 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
818 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
819 lhs_->Output(out, Precedence(), CYLeft(flags));
820 out << Operator();
821 }
822
823 void 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
831 void CYScript::Output(CYOutput &out) const {
832 out << code_;
833 }
834
835 void CYProperty::Output(CYOutput &out) const {
836 if (next_ != NULL || out.pretty_)
837 out << ',';
838 out << '\n' << next_;
839 }
840
841 void CYPropertyGetter::Output(CYOutput &out) const {
842 out << "get" << ' ';
843 name_->PropertyName(out);
844 CYFunction::Output(out);
845 CYProperty::Output(out);
846 }
847
848 void CYPropertyMethod::Output(CYOutput &out) const {
849 name_->PropertyName(out);
850 CYFunction::Output(out);
851 CYProperty::Output(out);
852 }
853
854 void CYPropertySetter::Output(CYOutput &out) const {
855 out << "set" << ' ';
856 name_->PropertyName(out);
857 CYFunction::Output(out);
858 CYProperty::Output(out);
859 }
860
861 void 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
869 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
870 out << Value();
871 }
872
873 void 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
881 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
882 out << "return";
883 if (value_ != NULL)
884 out << ' ' << *value_;
885 out << ';';
886 }
887
888 void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
889 lhs_->Output(out, CYLeft(flags));
890 out << ' ';
891 proc_->Output(out, CYRight(flags));
892 }
893
894 void 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
902 void CYSubscriptMember::Output(CYOutput &out, CYFlags flags) const {
903 object_->Output(out, Precedence(), CYLeft(flags));
904 out << "." << '[' << *property_ << ']';
905 }
906
907 void 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
919 void 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
941 void CYString::Output(CYOutput &out, CYFlags flags) const {
942 std::ostringstream str;
943 CYStringify(str, value_, size_);
944 out << str.str().c_str();
945 }
946
947 void CYString::PropertyName(CYOutput &out) const {
948 if (const char *word = Word())
949 out << word;
950 else
951 out << *this;
952 }
953
954 static 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
976 const 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
989 void CYStructDefinition::Output(CYOutput &out, CYFlags flags) const {
990 out << "struct" << ' ' << *name_ << *tail_;
991 }
992
993 void 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
1005 void 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
1013 void CYSuperCall::Output(CYOutput &out, CYFlags flags) const {
1014 out << "super" << '(' << arguments_ << ')';
1015 }
1016
1017 void 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
1025 void 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
1034 void CYThis::Output(CYOutput &out, CYFlags flags) const {
1035 out << "this";
1036 }
1037
1038 namespace cy {
1039 namespace Syntax {
1040
1041 void Throw::Output(CYOutput &out, CYFlags flags) const {
1042 out << "throw";
1043 if (value_ != NULL)
1044 out << ' ' << *value_;
1045 out << ';';
1046 }
1047
1048 void 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
1060 void 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
1070 void 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
1099 void CYTypeError::Output(CYOutput &out) const {
1100 out << "@error";
1101 }
1102
1103 void 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
1113 void 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
1125 void CYTypeStruct::Output(CYOutput &out) const {
1126 out << "struct";
1127 if (name_ != NULL)
1128 out << ' ' << *name_;
1129 else
1130 out << *tail_;
1131 }
1132
1133 void 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
1143 void CYTypeVariable::Output(CYOutput &out) const {
1144 out << *name_;
1145 }
1146
1147 void CYTypeVoid::Output(CYOutput &out) const {
1148 out << "void";
1149 }
1150
1151 void CYVar::Output(CYOutput &out, CYFlags flags) const {
1152 out << "var" << ' ';
1153 bindings_->Output(out, flags); // XXX: flags
1154 out << ';';
1155 }
1156
1157 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
1158 out << *name_;
1159 }
1160
1161 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
1162 out << "while" << ' ' << '(' << *test_ << ')';
1163 code_->Single(out, CYRight(flags), CYCompactShort);
1164 }
1165
1166 void CYWith::Output(CYOutput &out, CYFlags flags) const {
1167 out << "with" << ' ' << '(' << *scope_ << ')';
1168 code_->Single(out, CYRight(flags), CYCompactShort);
1169 }
1170
1171 void 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
1181 void CYWord::PropertyName(CYOutput &out) const {
1182 Output(out);
1183 }
1184
1185 const char *CYWord::Word() const {
1186 return word_;
1187 }