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