]> git.saurik.com Git - cycript.git/blob - Output.cpp
e8ae4aeb7071890a4bf7af8f41df49759b0b1743
[cycript.git] / Output.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 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);
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);
677 out << ')' << '(' << parameters_ << ')';
678 }
679
680 void CYTypeConstant::Output(CYOutput &out, CYIdentifier *identifier) const {
681 out << "const" << ' ';
682 next_->Output(out, Precedence(), identifier);
683 }
684
685 void CYTypeFunctionWith::Output(CYOutput &out, CYIdentifier *identifier) const {
686 next_->Output(out, Precedence(), identifier);
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);
699 }
700
701 void CYTypeVolatile::Output(CYOutput &out, CYIdentifier *identifier) const {
702 out << "volatile";
703 next_->Output(out, Precedence(), identifier);
704 }
705
706 void CYTypeModifier::Output(CYOutput &out, int precedence, CYIdentifier *identifier) const {
707 if (this == NULL) {
708 out << identifier;
709 return;
710 }
711
712 bool protect(precedence > Precedence());
713
714 if (protect)
715 out << '(';
716 Output(out, identifier);
717 if (protect)
718 out << ')';
719 }
720
721 void CYTypedIdentifier::Output(CYOutput &out) const {
722 specifier_->Output(out);
723 modifier_->Output(out, 0, identifier_);
724 }
725
726 void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
727 out << "@encode(" << typed_ << ")";
728 }
729
730 void CYTypedParameter::Output(CYOutput &out) const {
731 out << typed_;
732 if (next_ != NULL)
733 out << ',' << ' ' << next_;
734 }
735
736 void CYLambda::Output(CYOutput &out, CYFlags flags) const {
737 // XXX: this is seriously wrong
738 out << "[](";
739 out << ")->";
740 out << "{";
741 out << "}";
742 }
743
744 void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
745 out << "typedef" << ' ' << *typed_;
746 out.Terminate();
747 }
748
749 void CYTypeExpression::Output(CYOutput &out, CYFlags flags) const {
750 out << '(' << "typedef" << ' ' << *typed_ << ')';
751 }
752
753 void CYLexical::Output(CYOutput &out, CYFlags flags) const {
754 out << "let" << ' ';
755 bindings_->Output(out, flags); // XXX: flags
756 out << ';';
757 }
758
759 void CYModule::Output(CYOutput &out) const {
760 out << part_;
761 if (next_ != NULL)
762 out << '.' << next_;
763 }
764
765 namespace cy {
766 namespace Syntax {
767
768 void New::Output(CYOutput &out, CYFlags flags) const {
769 out << "new" << ' ';
770 CYFlags jacks(CYNoCall | CYCenter(flags));
771 constructor_->Output(out, Precedence(), jacks);
772 if (arguments_ != NULL)
773 out << '(' << *arguments_ << ')';
774 }
775
776 } }
777
778 void CYNull::Output(CYOutput &out, CYFlags flags) const {
779 out << "null";
780 }
781
782 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
783 std::ostringstream str;
784 CYNumerify(str, Value());
785 std::string value(str.str());
786 out << value.c_str();
787 // XXX: this should probably also handle hex conversions and exponents
788 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
789 out << '.';
790 }
791
792 void CYNumber::PropertyName(CYOutput &out) const {
793 Output(out, CYNoFlags);
794 }
795
796 void CYObject::Output(CYOutput &out, CYFlags flags) const {
797 bool protect((flags & CYNoBrace) != 0);
798 if (protect)
799 out << '(';
800 out << '{' << '\n';
801 ++out.indent_;
802 out << properties_;
803 --out.indent_;
804 out << '\t' << '}';
805 if (protect)
806 out << ')';
807 }
808
809 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
810 lhs_->Output(out, Precedence(), CYLeft(flags));
811 out << Operator();
812 }
813
814 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
815 const char *name(Operator());
816 out << name;
817 if (Alphabetic())
818 out << ' ';
819 rhs_->Output(out, Precedence(), CYRight(flags));
820 }
821
822 void CYScript::Output(CYOutput &out) const {
823 out << code_;
824 }
825
826 void CYProperty::Output(CYOutput &out) const {
827 if (next_ != NULL || out.pretty_)
828 out << ',';
829 out << '\n' << next_;
830 }
831
832 void CYPropertyGetter::Output(CYOutput &out) const {
833 out << "get" << ' ';
834 name_->PropertyName(out);
835 CYFunction::Output(out);
836 CYProperty::Output(out);
837 }
838
839 void CYPropertyMethod::Output(CYOutput &out) const {
840 name_->PropertyName(out);
841 CYFunction::Output(out);
842 CYProperty::Output(out);
843 }
844
845 void CYPropertySetter::Output(CYOutput &out) const {
846 out << "set" << ' ';
847 name_->PropertyName(out);
848 CYFunction::Output(out);
849 CYProperty::Output(out);
850 }
851
852 void CYPropertyValue::Output(CYOutput &out) const {
853 out << '\t';
854 name_->PropertyName(out);
855 out << ':' << ' ';
856 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
857 CYProperty::Output(out);
858 }
859
860 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
861 out << Value();
862 }
863
864 void CYResolveMember::Output(CYOutput &out, CYFlags flags) const {
865 object_->Output(out, Precedence(), CYLeft(flags));
866 if (const char *word = property_->Word())
867 out << "::" << word;
868 else
869 out << "::" << '[' << *property_ << ']';
870 }
871
872 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
873 out << "return";
874 if (value_ != NULL)
875 out << ' ' << *value_;
876 out << ';';
877 }
878
879 void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
880 lhs_->Output(out, CYLeft(flags));
881 out << ' ';
882 proc_->Output(out, CYRight(flags));
883 }
884
885 void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
886 out << '{' << ' ' << '|' << parameters_ << '|' << '\n';
887 ++out.indent_;
888 out << code_;
889 --out.indent_;
890 out << '\t' << '}';
891 }
892
893 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
894 bool first(true);
895 CYForEach (next, this) {
896 bool last(next->next_ == NULL);
897 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
898 first = false;
899 out << '\t';
900 next->Output(out, jacks);
901 out << '\n';
902 }
903 }
904
905 void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) const {
906 if (this == NULL)
907 return out.Terminate();
908
909 _assert(next_ == NULL);
910
911 CYCompactType compact(Compact());
912
913 if (compact >= request)
914 out << ' ';
915 else {
916 out << '\n';
917 ++out.indent_;
918 out << '\t';
919 }
920
921 Output(out, flags);
922
923 if (compact < request)
924 --out.indent_;
925 }
926
927 void CYString::Output(CYOutput &out, CYFlags flags) const {
928 std::ostringstream str;
929 CYStringify(str, value_, size_);
930 out << str.str().c_str();
931 }
932
933 void CYString::PropertyName(CYOutput &out) const {
934 if (const char *word = Word())
935 out << word;
936 else
937 out << *this;
938 }
939
940 static const char *Reserved_[] = {
941 "false", "null", "true",
942
943 "break", "case", "catch", "continue", "default",
944 "delete", "do", "else", "finally", "for", "function",
945 "if", "in", "instanceof", "new", "return", "switch",
946 "this", "throw", "try", "typeof", "var", "void",
947 "while", "with",
948
949 "debugger", "const",
950
951 "class", "enum", "export", "extends", "import", "super",
952
953 "abstract", "boolean", "byte", "char", "double", "final",
954 "float", "goto", "int", "long", "native", "short",
955 "synchronized", "throws", "transient", "volatile",
956
957 "let", "yield",
958
959 NULL
960 };
961
962 const char *CYString::Word() const {
963 if (size_ == 0 || !WordStartRange_[value_[0]])
964 return NULL;
965 for (size_t i(1); i != size_; ++i)
966 if (!WordEndRange_[value_[i]])
967 return NULL;
968 const char *value(Value());
969 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
970 if (strcmp(*reserved, value) == 0)
971 return NULL;
972 return value;
973 }
974
975 void CYStructDefinition::Output(CYOutput &out, CYFlags flags) const {
976 out << "struct" << ' ' << *name_ << *tail_;
977 }
978
979 void CYStructTail::Output(CYOutput &out) const {
980 out << ' ' << '{' << '\n';
981 ++out.indent_;
982 CYForEach (field, fields_) {
983 out << '\t' << *field->typed_;
984 out.Terminate();
985 out << '\n';
986 }
987 --out.indent_;
988 out << '}';
989 }
990
991 void CYSuperAccess::Output(CYOutput &out, CYFlags flags) const {
992 out << "super";
993 if (const char *word = property_->Word())
994 out << '.' << word;
995 else
996 out << '[' << *property_ << ']';
997 }
998
999 void CYSuperCall::Output(CYOutput &out, CYFlags flags) const {
1000 out << "super" << '(' << arguments_ << ')';
1001 }
1002
1003 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
1004 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{' << '\n';
1005 ++out.indent_;
1006 out << clauses_;
1007 --out.indent_;
1008 out << '\t' << '}';
1009 }
1010
1011 void CYSymbol::Output(CYOutput &out, CYFlags flags) const {
1012 bool protect((flags & CYNoColon) != 0);
1013 if (protect)
1014 out << '(';
1015 out << ':' << name_;
1016 if (protect)
1017 out << ')';
1018 }
1019
1020 void CYThis::Output(CYOutput &out, CYFlags flags) const {
1021 out << "this";
1022 }
1023
1024 namespace cy {
1025 namespace Syntax {
1026
1027 void Throw::Output(CYOutput &out, CYFlags flags) const {
1028 out << "throw";
1029 if (value_ != NULL)
1030 out << ' ' << *value_;
1031 out << ';';
1032 }
1033
1034 void Try::Output(CYOutput &out, CYFlags flags) const {
1035 out << "try" << ' ';
1036 out << '{' << '\n';
1037 ++out.indent_;
1038 out << code_;
1039 --out.indent_;
1040 out << '\t' << '}';
1041 out << catch_ << finally_;
1042 }
1043
1044 } }
1045
1046 void CYTypeCharacter::Output(CYOutput &out) const {
1047 switch (signing_) {
1048 case CYTypeNeutral: break;
1049 case CYTypeSigned: out << "signed" << ' '; break;
1050 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1051 }
1052
1053 out << "char";
1054 }
1055
1056 void CYTypeError::Output(CYOutput &out) const {
1057 out << "@error";
1058 }
1059
1060 void CYTypeIntegral::Output(CYOutput &out) const {
1061 if (signing_ == CYTypeUnsigned)
1062 out << "unsigned" << ' ';
1063 switch (length_) {
1064 case 0: out << "short"; break;
1065 case 1: out << "int"; break;
1066 case 2: out << "long"; break;
1067 case 3: out << "long" << ' ' << "long"; break;
1068 default: _assert(false);
1069 }
1070 }
1071
1072 void CYTypeStruct::Output(CYOutput &out) const {
1073 out << "struct";
1074 if (name_ != NULL)
1075 out << ' ' << *name_;
1076 else
1077 out << *tail_;
1078 }
1079
1080 void CYTypeReference::Output(CYOutput &out) const {
1081 out << "struct" << ' ' << *name_;
1082 }
1083
1084 void CYTypeVariable::Output(CYOutput &out) const {
1085 out << *name_;
1086 }
1087
1088 void CYTypeVoid::Output(CYOutput &out) const {
1089 out << "void";
1090 }
1091
1092 void CYVar::Output(CYOutput &out, CYFlags flags) const {
1093 out << "var" << ' ';
1094 bindings_->Output(out, flags); // XXX: flags
1095 out << ';';
1096 }
1097
1098 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
1099 out << *name_;
1100 }
1101
1102 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
1103 out << "while" << ' ' << '(' << *test_ << ')';
1104 code_->Single(out, CYRight(flags), CYCompactShort);
1105 }
1106
1107 void CYWith::Output(CYOutput &out, CYFlags flags) const {
1108 out << "with" << ' ' << '(' << *scope_ << ')';
1109 code_->Single(out, CYRight(flags), CYCompactShort);
1110 }
1111
1112 void CYWord::Output(CYOutput &out) const {
1113 out << Word();
1114 if (out.options_.verbose_) {
1115 out('@');
1116 char number[32];
1117 sprintf(number, "%p", this);
1118 out(number);
1119 }
1120 }
1121
1122 void CYWord::PropertyName(CYOutput &out) const {
1123 Output(out);
1124 }
1125
1126 const char *CYWord::Word() const {
1127 return word_;
1128 }