]> git.saurik.com Git - cycript.git/blame_incremental - Output.cpp
Add all supported binding API headers to analysis.
[cycript.git] / Output.cpp
... / ...
CommitLineData
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
28void CYStringify(std::ostringstream &str, const char *data, size_t size, bool c) {
29 bool single;
30 if (c)
31 single = false;
32 else {
33 unsigned quot(0), apos(0);
34 for (const char *value(data), *end(data + size); value != end; ++value)
35 if (*value == '"')
36 ++quot;
37 else if (*value == '\'')
38 ++apos;
39
40 single = quot > apos;
41 }
42
43 str << (single ? '\'' : '"');
44
45 for (const char *value(data), *end(data + size); value != end; ++value)
46 switch (uint8_t next = *value) {
47 case '\\': str << "\\\\"; break;
48 case '\b': str << "\\b"; break;
49 case '\f': str << "\\f"; break;
50 case '\n': str << "\\n"; break;
51 case '\r': str << "\\r"; break;
52 case '\t': str << "\\t"; break;
53 case '\v': str << "\\v"; break;
54
55 case '"':
56 if (!single)
57 str << "\\\"";
58 else goto simple;
59 break;
60
61 case '\'':
62 if (single)
63 str << "\\'";
64 else goto simple;
65 break;
66
67 case '\0':
68 if (value[1] >= '0' && value[1] <= '9')
69 str << "\\x00";
70 else
71 str << "\\0";
72 break;
73
74 default:
75 if (next >= 0x20 && next < 0x7f) simple:
76 str << *value;
77 else {
78 unsigned levels(1);
79 if ((next & 0x80) != 0)
80 while ((next & 0x80 >> ++levels) != 0);
81
82 unsigned point(next & 0xff >> levels);
83 while (--levels != 0)
84 point = point << 6 | uint8_t(*++value) & 0x3f;
85
86 if (point < 0x100)
87 str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << point;
88 else if (point < 0x10000)
89 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << point;
90 else {
91 point -= 0x10000;
92 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xd800 | point >> 0x0a);
93 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xdc00 | point & 0x3ff);
94 }
95 }
96 }
97
98 str << (single ? '\'' : '"');
99}
100
101void CYNumerify(std::ostringstream &str, double value) {
102 if (std::isinf(value)) {
103 if (value < 0)
104 str << '-';
105 str << "Infinity";
106 return;
107 }
108
109 char string[32];
110 // XXX: I want this to print 1e3 rather than 1000
111 sprintf(string, "%.17g", value);
112 str << string;
113}
114
115void CYOutput::Terminate() {
116 operator ()(';');
117 mode_ = NoMode;
118}
119
120CYOutput &CYOutput::operator <<(char rhs) {
121 if (rhs == ' ' || rhs == '\n')
122 if (pretty_)
123 operator ()(rhs);
124 else goto done;
125 else if (rhs == '\t')
126 if (pretty_)
127 for (unsigned i(0); i != indent_; ++i)
128 operator ()(" ", 4);
129 else goto done;
130 else if (rhs == '\r') {
131 if (right_) {
132 operator ()('\n');
133 right_ = false;
134 } goto done;
135 } else goto work;
136
137 right_ = true;
138 mode_ = NoMode;
139 goto done;
140
141 work:
142 if (mode_ == Terminated && rhs != '}') {
143 right_ = true;
144 operator ()(';');
145 }
146
147 if (rhs == ';') {
148 if (pretty_)
149 goto none;
150 else {
151 mode_ = Terminated;
152 goto done;
153 }
154 } else if (rhs == '+') {
155 if (mode_ == NoPlus)
156 operator ()(' ');
157 mode_ = NoPlus;
158 } else if (rhs == '-') {
159 if (mode_ == NoHyphen)
160 operator ()(' ');
161 mode_ = NoHyphen;
162 } else if (WordEndRange_[rhs]) {
163 if (mode_ == NoLetter)
164 operator ()(' ');
165 mode_ = NoLetter;
166 } else none:
167 mode_ = NoMode;
168
169 right_ = true;
170 operator ()(rhs);
171 done:
172 return *this;
173}
174
175CYOutput &CYOutput::operator <<(const char *rhs) {
176 size_t size(strlen(rhs));
177
178 if (size == 1)
179 return *this << *rhs;
180
181 if (mode_ == Terminated)
182 operator ()(';');
183 else if (
184 mode_ == NoPlus && *rhs == '+' ||
185 mode_ == NoHyphen && *rhs == '-' ||
186 mode_ == NoLetter && WordEndRange_[*rhs]
187 )
188 operator ()(' ');
189
190 char last(rhs[size - 1]);
191 if (WordEndRange_[last] || last == '/')
192 mode_ = NoLetter;
193 else
194 mode_ = NoMode;
195
196 right_ = true;
197 operator ()(rhs, size);
198 return *this;
199}
200
201void CYArgument::Output(CYOutput &out) const {
202 if (name_ != NULL) {
203 out << *name_;
204 if (value_ != NULL)
205 out << ':' << ' ';
206 }
207 if (value_ != NULL)
208 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
209 if (next_ != NULL) {
210 out << ',';
211 out << ' ' << *next_;
212 }
213}
214
215void CYArray::Output(CYOutput &out, CYFlags flags) const {
216 out << '[' << elements_ << ']';
217}
218
219void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
220 out << '[' << *expression_ << ' ' << *comprehensions_ << ']';
221}
222
223void CYAssignment::Output(CYOutput &out, CYFlags flags) const {
224 lhs_->Output(out, Precedence() - 1, CYLeft(flags) | CYNoRightHand);
225 out << ' ' << Operator() << ' ';
226 rhs_->Output(out, Precedence(), CYRight(flags));
227}
228
229void CYBlock::Output(CYOutput &out, CYFlags flags) const {
230 out << '{' << '\n';
231 ++out.indent_;
232 out << code_;
233 --out.indent_;
234 out << '\t' << '}';
235}
236
237void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
238 out << '!' << (Value() ? "0" : "1");
239 if ((flags & CYNoInteger) != 0)
240 out << '.';
241}
242
243void CYBreak::Output(CYOutput &out, CYFlags flags) const {
244 out << "break";
245 if (label_ != NULL)
246 out << ' ' << *label_;
247 out << ';';
248}
249
250void CYCall::Output(CYOutput &out, CYFlags flags) const {
251 bool protect((flags & CYNoCall) != 0);
252 if (protect)
253 out << '(';
254 function_->Output(out, Precedence(), protect ? CYNoFlags : flags);
255 out << '(' << arguments_ << ')';
256 if (protect)
257 out << ')';
258}
259
260namespace cy {
261namespace Syntax {
262
263void Catch::Output(CYOutput &out) const {
264 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ';
265 out << '{' << '\n';
266 ++out.indent_;
267 out << code_;
268 --out.indent_;
269 out << '\t' << '}';
270}
271
272} }
273
274void CYClassExpression::Output(CYOutput &out, CYFlags flags) const {
275 bool protect((flags & CYNoClass) != 0);
276 if (protect)
277 out << '(';
278 out << "class";
279 if (name_ != NULL)
280 out << ' ' << *name_;
281 out << *tail_;;
282 if (protect)
283 out << ')';
284}
285
286void CYClassStatement::Output(CYOutput &out, CYFlags flags) const {
287 out << "class" << ' ' << *name_ << *tail_;
288}
289
290void CYClassTail::Output(CYOutput &out) const {
291 if (extends_ == NULL)
292 out << ' ';
293 else {
294 out << '\n';
295 ++out.indent_;
296 out << "extends" << ' ';
297 extends_->Output(out, CYAssign::Precedence_ - 1, CYNoFlags);
298 out << '\n';
299 --out.indent_;
300 }
301
302 out << '{' << '\n';
303 ++out.indent_;
304
305 --out.indent_;
306 out << '}';
307}
308
309void CYCompound::Output(CYOutput &out, CYFlags flags) const {
310 if (next_ == NULL)
311 expression_->Output(out, flags);
312 else {
313 expression_->Output(out, CYLeft(flags));
314 out << ',' << ' ';
315 next_->Output(out, CYRight(flags));
316 }
317}
318
319void CYComputed::PropertyName(CYOutput &out) const {
320 out << '[';
321 expression_->Output(out, CYAssign::Precedence_, CYNoFlags);
322 out << ']';
323}
324
325void CYCondition::Output(CYOutput &out, CYFlags flags) const {
326 test_->Output(out, Precedence() - 1, CYLeft(flags));
327 out << ' ' << '?' << ' ';
328 if (true_ != NULL)
329 true_->Output(out, CYAssign::Precedence_, CYNoColon);
330 out << ' ' << ':' << ' ';
331 false_->Output(out, CYAssign::Precedence_, CYRight(flags));
332}
333
334void CYContinue::Output(CYOutput &out, CYFlags flags) const {
335 out << "continue";
336 if (label_ != NULL)
337 out << ' ' << *label_;
338 out << ';';
339}
340
341void CYClause::Output(CYOutput &out) const {
342 out << '\t';
343 if (value_ == NULL)
344 out << "default";
345 else {
346 out << "case" << ' ';
347 value_->Output(out, CYNoColon);
348 }
349 out << ':' << '\n';
350 ++out.indent_;
351 out << code_;
352 --out.indent_;
353 out << next_;
354}
355
356void CYDebugger::Output(CYOutput &out, CYFlags flags) const {
357 out << "debugger" << ';';
358}
359
360void CYBinding::Output(CYOutput &out, CYFlags flags) const {
361 out << *identifier_;
362 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
363 if (initializer_ != NULL) {
364 out << ' ' << '=' << ' ';
365 initializer_->Output(out, CYAssign::Precedence_, CYRight(flags));
366 }
367}
368
369void CYBindings::Output(CYOutput &out) const {
370 Output(out, CYNoFlags);
371}
372
373void CYBindings::Output(CYOutput &out, CYFlags flags) const {
374 const CYBindings *binding(this);
375 bool first(true);
376
377 for (;;) {
378 CYBindings *next(binding->next_);
379
380 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
381 first = false;
382 binding->binding_->Output(out, jacks);
383
384 if (next == NULL)
385 break;
386
387 out << ',' << ' ';
388 binding = next;
389 }
390}
391
392void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
393 object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger);
394 if (const char *word = property_->Word())
395 out << '.' << word;
396 else
397 out << '[' << *property_ << ']';
398}
399
400void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
401 out << "do";
402
403 unsigned line(out.position_.line);
404 unsigned indent(out.indent_);
405 code_->Single(out, CYCenter(flags), CYCompactLong);
406
407 if (out.position_.line != line && out.recent_ == indent)
408 out << ' ';
409 else
410 out << '\n' << '\t';
411
412 out << "while" << ' ' << '(' << *test_ << ')';
413}
414
415void CYElementSpread::Output(CYOutput &out) const {
416 out << "..." << value_;
417}
418
419void CYElementValue::Output(CYOutput &out) const {
420 if (value_ != NULL)
421 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
422 if (next_ != NULL || value_ == NULL) {
423 out << ',';
424 if (next_ != NULL && !next_->Elision())
425 out << ' ';
426 }
427 if (next_ != NULL)
428 next_->Output(out);
429}
430
431void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
432 out.Terminate();
433}
434
435void CYEval::Output(CYOutput &out, CYFlags flags) const {
436 _assert(false);
437}
438
439void CYExpress::Output(CYOutput &out, CYFlags flags) const {
440 expression_->Output(out, flags | CYNoBFC);
441 out << ';';
442}
443
444void CYExpression::Output(CYOutput &out) const {
445 Output(out, CYNoFlags);
446}
447
448void CYExpression::Output(CYOutput &out, int precedence, CYFlags flags) const {
449 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
450 out << '(' << *this << ')';
451 else
452 Output(out, flags);
453}
454
455void CYExtend::Output(CYOutput &out, CYFlags flags) const {
456 lhs_->Output(out, CYLeft(flags));
457 out << ' ' << object_;
458}
459
460void CYExternal::Output(CYOutput &out, CYFlags flags) const {
461 out << "extern" << abi_ << typed_;
462 out.Terminate();
463}
464
465void CYFatArrow::Output(CYOutput &out, CYFlags flags) const {
466 out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << '{' << code_ << '}';
467}
468
469void 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
478void 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
494void CYForLexical::Output(CYOutput &out, CYFlags flags) const {
495 out << (constant_ ? "const" : "let") << ' ';
496 binding_->Output(out, CYRight(flags));
497}
498
499void 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
506void 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
513void CYForInComprehension::Output(CYOutput &out) const {
514 out << "for" << ' ' << '(';
515 binding_->Output(out, CYNoIn | CYNoRightHand);
516 out << ' ' << "in" << ' ' << *iterable_ << ')';
517}
518
519void 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
526void CYForOfComprehension::Output(CYOutput &out) const {
527 out << "for" << ' ' << '(';
528 binding_->Output(out, CYNoRightHand);
529 out << ' ' << "of" << ' ' << *iterable_ << ')' << next_;
530}
531
532void CYForVariable::Output(CYOutput &out, CYFlags flags) const {
533 out << "var" << ' ';
534 binding_->Output(out, CYRight(flags));
535}
536
537void 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
546void 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
559void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
560 out << "function" << ' ' << *name_;
561 CYFunction::Output(out);
562}
563
564void CYFunctionParameter::Output(CYOutput &out) const {
565 binding_->Output(out, CYNoFlags);
566 if (next_ != NULL)
567 out << ',' << ' ' << *next_;
568}
569
570const char *CYIdentifier::Word() const {
571 return next_ == NULL || next_ == this ? CYWord::Word() : next_->Word();
572}
573
574void 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
609void CYIfComprehension::Output(CYOutput &out) const {
610 out << "if" << ' ' << '(' << *test_ << ')' << next_;
611}
612
613void CYImport::Output(CYOutput &out, CYFlags flags) const {
614 out << "@import";
615}
616
617void CYImportDeclaration::Output(CYOutput &out, CYFlags flags) const {
618 _assert(false);
619}
620
621void CYIndirect::Output(CYOutput &out, CYFlags flags) const {
622 out << "*";
623 rhs_->Output(out, Precedence(), CYRight(flags));
624}
625
626void 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
634void 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
648void CYLabel::Output(CYOutput &out, CYFlags flags) const {
649 out << *name_ << ':';
650 statement_->Single(out, CYRight(flags), CYCompactShort);
651}
652
653void CYParenthetical::Output(CYOutput &out, CYFlags flags) const {
654 out << '(';
655 expression_->Output(out, CYCompound::Precedence_, CYNoFlags);
656 out << ')';
657}
658
659void CYStatement::Output(CYOutput &out) const {
660 Multiple(out);
661}
662
663void CYTemplate::Output(CYOutput &out, CYFlags flags) const {
664 _assert(false);
665}
666
667void CYTypeArrayOf::Output(CYOutput &out, CYIdentifier *identifier) const {
668 next_->Output(out, Precedence(), identifier);
669 out << '[';
670 out << size_;
671 out << ']';
672}
673
674void CYTypeBlockWith::Output(CYOutput &out, CYIdentifier *identifier) const {
675 out << '(' << '^';
676 next_->Output(out, Precedence(), identifier);
677 out << ')' << '(' << parameters_ << ')';
678}
679
680void CYTypeConstant::Output(CYOutput &out, CYIdentifier *identifier) const {
681 out << "const" << ' ';
682 next_->Output(out, Precedence(), identifier);
683}
684
685void 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
696void CYTypePointerTo::Output(CYOutput &out, CYIdentifier *identifier) const {
697 out << '*';
698 next_->Output(out, Precedence(), identifier);
699}
700
701void CYTypeVolatile::Output(CYOutput &out, CYIdentifier *identifier) const {
702 out << "volatile";
703 next_->Output(out, Precedence(), identifier);
704}
705
706void 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
721void CYTypedIdentifier::Output(CYOutput &out) const {
722 specifier_->Output(out);
723 modifier_->Output(out, 0, identifier_);
724}
725
726void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
727 out << "@encode(" << typed_ << ")";
728}
729
730void CYTypedParameter::Output(CYOutput &out) const {
731 out << typed_;
732 if (next_ != NULL)
733 out << ',' << ' ' << next_;
734}
735
736void CYLambda::Output(CYOutput &out, CYFlags flags) const {
737 // XXX: this is seriously wrong
738 out << "[](";
739 out << ")->";
740 out << "{";
741 out << "}";
742}
743
744void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
745 out << "typedef" << ' ' << *typed_;
746 out.Terminate();
747}
748
749void CYTypeExpression::Output(CYOutput &out, CYFlags flags) const {
750 out << '(' << "typedef" << ' ' << *typed_ << ')';
751}
752
753void CYLexical::Output(CYOutput &out, CYFlags flags) const {
754 out << "let" << ' ';
755 bindings_->Output(out, flags); // XXX: flags
756 out << ';';
757}
758
759void CYModule::Output(CYOutput &out) const {
760 out << part_;
761 if (next_ != NULL)
762 out << '.' << next_;
763}
764
765namespace cy {
766namespace Syntax {
767
768void 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
778void CYNull::Output(CYOutput &out, CYFlags flags) const {
779 out << "null";
780}
781
782void 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
792void CYNumber::PropertyName(CYOutput &out) const {
793 Output(out, CYNoFlags);
794}
795
796void 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
809void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
810 lhs_->Output(out, Precedence(), CYLeft(flags));
811 out << Operator();
812}
813
814void 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
822void CYScript::Output(CYOutput &out) const {
823 out << code_;
824}
825
826void CYProperty::Output(CYOutput &out) const {
827 if (next_ != NULL || out.pretty_)
828 out << ',';
829 out << '\n' << next_;
830}
831
832void CYPropertyGetter::Output(CYOutput &out) const {
833 out << "get" << ' ';
834 name_->PropertyName(out);
835 CYFunction::Output(out);
836 CYProperty::Output(out);
837}
838
839void CYPropertyMethod::Output(CYOutput &out) const {
840 name_->PropertyName(out);
841 CYFunction::Output(out);
842 CYProperty::Output(out);
843}
844
845void CYPropertySetter::Output(CYOutput &out) const {
846 out << "set" << ' ';
847 name_->PropertyName(out);
848 CYFunction::Output(out);
849 CYProperty::Output(out);
850}
851
852void 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
860void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
861 out << Value();
862}
863
864void 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
872void CYReturn::Output(CYOutput &out, CYFlags flags) const {
873 out << "return";
874 if (value_ != NULL)
875 out << ' ' << *value_;
876 out << ';';
877}
878
879void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
880 lhs_->Output(out, CYLeft(flags));
881 out << ' ';
882 proc_->Output(out, CYRight(flags));
883}
884
885void 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
893void CYSubscriptMember::Output(CYOutput &out, CYFlags flags) const {
894 object_->Output(out, Precedence(), CYLeft(flags));
895 out << "." << '[' << *property_ << ']';
896}
897
898void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
899 bool first(true);
900 CYForEach (next, this) {
901 bool last(next->next_ == NULL);
902 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
903 first = false;
904 out << '\t';
905 next->Output(out, jacks);
906 out << '\n';
907 }
908}
909
910void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) const {
911 if (this == NULL)
912 return out.Terminate();
913
914 _assert(next_ == NULL);
915
916 CYCompactType compact(Compact());
917
918 if (compact >= request)
919 out << ' ';
920 else {
921 out << '\n';
922 ++out.indent_;
923 out << '\t';
924 }
925
926 Output(out, flags);
927
928 if (compact < request)
929 --out.indent_;
930}
931
932void CYString::Output(CYOutput &out, CYFlags flags) const {
933 std::ostringstream str;
934 CYStringify(str, value_, size_);
935 out << str.str().c_str();
936}
937
938void CYString::PropertyName(CYOutput &out) const {
939 if (const char *word = Word())
940 out << word;
941 else
942 out << *this;
943}
944
945static const char *Reserved_[] = {
946 "false", "null", "true",
947
948 "break", "case", "catch", "continue", "default",
949 "delete", "do", "else", "finally", "for", "function",
950 "if", "in", "instanceof", "new", "return", "switch",
951 "this", "throw", "try", "typeof", "var", "void",
952 "while", "with",
953
954 "debugger", "const",
955
956 "class", "enum", "export", "extends", "import", "super",
957
958 "abstract", "boolean", "byte", "char", "double", "final",
959 "float", "goto", "int", "long", "native", "short",
960 "synchronized", "throws", "transient", "volatile",
961
962 "let", "yield",
963
964 NULL
965};
966
967const char *CYString::Word() const {
968 if (size_ == 0 || !WordStartRange_[value_[0]])
969 return NULL;
970 for (size_t i(1); i != size_; ++i)
971 if (!WordEndRange_[value_[i]])
972 return NULL;
973 const char *value(Value());
974 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
975 if (strcmp(*reserved, value) == 0)
976 return NULL;
977 return value;
978}
979
980void CYStructDefinition::Output(CYOutput &out, CYFlags flags) const {
981 out << "struct" << ' ' << *name_ << *tail_;
982}
983
984void CYStructTail::Output(CYOutput &out) const {
985 out << ' ' << '{' << '\n';
986 ++out.indent_;
987 CYForEach (field, fields_) {
988 out << '\t' << *field->typed_;
989 out.Terminate();
990 out << '\n';
991 }
992 --out.indent_;
993 out << '}';
994}
995
996void CYSuperAccess::Output(CYOutput &out, CYFlags flags) const {
997 out << "super";
998 if (const char *word = property_->Word())
999 out << '.' << word;
1000 else
1001 out << '[' << *property_ << ']';
1002}
1003
1004void CYSuperCall::Output(CYOutput &out, CYFlags flags) const {
1005 out << "super" << '(' << arguments_ << ')';
1006}
1007
1008void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
1009 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{' << '\n';
1010 ++out.indent_;
1011 out << clauses_;
1012 --out.indent_;
1013 out << '\t' << '}';
1014}
1015
1016void CYSymbol::Output(CYOutput &out, CYFlags flags) const {
1017 bool protect((flags & CYNoColon) != 0);
1018 if (protect)
1019 out << '(';
1020 out << ':' << name_;
1021 if (protect)
1022 out << ')';
1023}
1024
1025void CYThis::Output(CYOutput &out, CYFlags flags) const {
1026 out << "this";
1027}
1028
1029namespace cy {
1030namespace Syntax {
1031
1032void Throw::Output(CYOutput &out, CYFlags flags) const {
1033 out << "throw";
1034 if (value_ != NULL)
1035 out << ' ' << *value_;
1036 out << ';';
1037}
1038
1039void Try::Output(CYOutput &out, CYFlags flags) const {
1040 out << "try" << ' ';
1041 out << '{' << '\n';
1042 ++out.indent_;
1043 out << code_;
1044 --out.indent_;
1045 out << '\t' << '}';
1046 out << catch_ << finally_;
1047}
1048
1049} }
1050
1051void CYTypeCharacter::Output(CYOutput &out) const {
1052 switch (signing_) {
1053 case CYTypeNeutral: break;
1054 case CYTypeSigned: out << "signed" << ' '; break;
1055 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1056 }
1057
1058 out << "char";
1059}
1060
1061void CYTypeError::Output(CYOutput &out) const {
1062 out << "@error";
1063}
1064
1065void CYTypeIntegral::Output(CYOutput &out) const {
1066 if (signing_ == CYTypeUnsigned)
1067 out << "unsigned" << ' ';
1068 switch (length_) {
1069 case 0: out << "short"; break;
1070 case 1: out << "int"; break;
1071 case 2: out << "long"; break;
1072 case 3: out << "long" << ' ' << "long"; break;
1073 default: _assert(false);
1074 }
1075}
1076
1077void CYTypeStruct::Output(CYOutput &out) const {
1078 out << "struct";
1079 if (name_ != NULL)
1080 out << ' ' << *name_;
1081 else
1082 out << *tail_;
1083}
1084
1085void CYTypeReference::Output(CYOutput &out) const {
1086 out << "struct" << ' ' << *name_;
1087}
1088
1089void CYTypeVariable::Output(CYOutput &out) const {
1090 out << *name_;
1091}
1092
1093void CYTypeVoid::Output(CYOutput &out) const {
1094 out << "void";
1095}
1096
1097void CYVar::Output(CYOutput &out, CYFlags flags) const {
1098 out << "var" << ' ';
1099 bindings_->Output(out, flags); // XXX: flags
1100 out << ';';
1101}
1102
1103void CYVariable::Output(CYOutput &out, CYFlags flags) const {
1104 out << *name_;
1105}
1106
1107void CYWhile::Output(CYOutput &out, CYFlags flags) const {
1108 out << "while" << ' ' << '(' << *test_ << ')';
1109 code_->Single(out, CYRight(flags), CYCompactShort);
1110}
1111
1112void CYWith::Output(CYOutput &out, CYFlags flags) const {
1113 out << "with" << ' ' << '(' << *scope_ << ')';
1114 code_->Single(out, CYRight(flags), CYCompactShort);
1115}
1116
1117void CYWord::Output(CYOutput &out) const {
1118 out << Word();
1119 if (out.options_.verbose_) {
1120 out('@');
1121 char number[32];
1122 sprintf(number, "%p", this);
1123 out(number);
1124 }
1125}
1126
1127void CYWord::PropertyName(CYOutput &out) const {
1128 Output(out);
1129}
1130
1131const char *CYWord::Word() const {
1132 return word_;
1133}