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