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