]> git.saurik.com Git - cycript.git/blob - Output.cpp
Transform ECMAScript 6 import as CommonJS require.
[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 "cycript.hpp"
23
24 #include <sstream>
25
26 #include "Syntax.hpp"
27
28 void CYOutput::Terminate() {
29 operator ()(';');
30 mode_ = NoMode;
31 }
32
33 CYOutput &CYOutput::operator <<(char rhs) {
34 if (rhs == ' ' || rhs == '\n')
35 if (pretty_)
36 operator ()(rhs);
37 else goto done;
38 else if (rhs == '\t')
39 if (pretty_)
40 for (unsigned i(0); i != indent_; ++i)
41 operator ()(" ", 4);
42 else goto done;
43 else if (rhs == '\r') {
44 if (right_) {
45 operator ()('\n');
46 right_ = false;
47 } goto done;
48 } else goto work;
49
50 right_ = true;
51 mode_ = NoMode;
52 goto done;
53
54 work:
55 if (mode_ == Terminated && rhs != '}') {
56 right_ = true;
57 operator ()(';');
58 }
59
60 if (rhs == ';') {
61 if (pretty_)
62 goto none;
63 else {
64 mode_ = Terminated;
65 goto done;
66 }
67 } else if (rhs == '+') {
68 if (mode_ == NoPlus)
69 operator ()(' ');
70 mode_ = NoPlus;
71 } else if (rhs == '-') {
72 if (mode_ == NoHyphen)
73 operator ()(' ');
74 mode_ = NoHyphen;
75 } else if (WordEndRange_[rhs]) {
76 if (mode_ == NoLetter)
77 operator ()(' ');
78 mode_ = NoLetter;
79 } else none:
80 mode_ = NoMode;
81
82 right_ = true;
83 operator ()(rhs);
84 done:
85 return *this;
86 }
87
88 CYOutput &CYOutput::operator <<(const char *rhs) {
89 size_t size(strlen(rhs));
90
91 if (size == 1)
92 return *this << *rhs;
93
94 if (mode_ == Terminated)
95 operator ()(';');
96 else if (
97 mode_ == NoPlus && *rhs == '+' ||
98 mode_ == NoHyphen && *rhs == '-' ||
99 mode_ == NoLetter && WordEndRange_[*rhs]
100 )
101 operator ()(' ');
102
103 char last(rhs[size - 1]);
104 if (WordEndRange_[last] || last == '/')
105 mode_ = NoLetter;
106 else
107 mode_ = NoMode;
108
109 right_ = true;
110 operator ()(rhs, size);
111 return *this;
112 }
113
114 void CYArgument::Output(CYOutput &out) const {
115 if (name_ != NULL) {
116 out << *name_;
117 if (value_ != NULL)
118 out << ':' << ' ';
119 }
120 if (value_ != NULL)
121 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
122 if (next_ != NULL) {
123 out << ',';
124 out << ' ' << *next_;
125 }
126 }
127
128 void CYArray::Output(CYOutput &out, CYFlags flags) const {
129 out << '[' << elements_ << ']';
130 }
131
132 void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
133 out << '[' << *expression_ << ' ' << *comprehensions_ << ']';
134 }
135
136 void CYAssignment::Output(CYOutput &out, CYFlags flags) const {
137 lhs_->Output(out, Precedence() - 1, CYLeft(flags) | CYNoRightHand);
138 out << ' ' << Operator() << ' ';
139 rhs_->Output(out, Precedence(), CYRight(flags));
140 }
141
142 void CYBlock::Output(CYOutput &out, CYFlags flags) const {
143 out << '{' << '\n';
144 ++out.indent_;
145 out << code_;
146 --out.indent_;
147 out << '\t' << '}';
148 }
149
150 void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
151 out << '!' << (Value() ? "0" : "1");
152 if ((flags & CYNoInteger) != 0)
153 out << '.';
154 }
155
156 void CYBreak::Output(CYOutput &out, CYFlags flags) const {
157 out << "break";
158 if (label_ != NULL)
159 out << ' ' << *label_;
160 out << ';';
161 }
162
163 void CYCall::Output(CYOutput &out, CYFlags flags) const {
164 bool protect((flags & CYNoCall) != 0);
165 if (protect)
166 out << '(';
167 function_->Output(out, Precedence(), protect ? CYNoFlags : flags);
168 out << '(' << arguments_ << ')';
169 if (protect)
170 out << ')';
171 }
172
173 namespace cy {
174 namespace Syntax {
175
176 void Catch::Output(CYOutput &out) const {
177 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ';
178 out << '{' << '\n';
179 ++out.indent_;
180 out << code_;
181 --out.indent_;
182 out << '\t' << '}';
183 }
184
185 } }
186
187 void CYClassExpression::Output(CYOutput &out, CYFlags flags) const {
188 bool protect((flags & CYNoClass) != 0);
189 if (protect)
190 out << '(';
191 out << "class";
192 if (name_ != NULL)
193 out << ' ' << *name_;
194 out << *tail_;;
195 if (protect)
196 out << ')';
197 }
198
199 void CYClassStatement::Output(CYOutput &out, CYFlags flags) const {
200 out << "class" << ' ' << *name_ << *tail_;
201 }
202
203 void CYClassTail::Output(CYOutput &out) const {
204 if (extends_ == NULL)
205 out << ' ';
206 else {
207 out << '\n';
208 ++out.indent_;
209 out << "extends" << ' ';
210 extends_->Output(out, CYAssign::Precedence_ - 1, CYNoFlags);
211 out << '\n';
212 --out.indent_;
213 }
214
215 out << '{' << '\n';
216 ++out.indent_;
217
218 --out.indent_;
219 out << '}';
220 }
221
222 void CYCompound::Output(CYOutput &out, CYFlags flags) const {
223 if (next_ == NULL)
224 expression_->Output(out, flags);
225 else {
226 expression_->Output(out, CYLeft(flags));
227 out << ',' << ' ';
228 next_->Output(out, CYRight(flags));
229 }
230 }
231
232 void CYComputed::PropertyName(CYOutput &out) const {
233 out << '[';
234 expression_->Output(out, CYAssign::Precedence_, CYNoFlags);
235 out << ']';
236 }
237
238 void CYCondition::Output(CYOutput &out, CYFlags flags) const {
239 test_->Output(out, Precedence() - 1, CYLeft(flags));
240 out << ' ' << '?' << ' ';
241 if (true_ != NULL)
242 true_->Output(out, CYAssign::Precedence_, CYNoFlags);
243 out << ' ' << ':' << ' ';
244 false_->Output(out, CYAssign::Precedence_, CYRight(flags));
245 }
246
247 void CYContinue::Output(CYOutput &out, CYFlags flags) const {
248 out << "continue";
249 if (label_ != NULL)
250 out << ' ' << *label_;
251 out << ';';
252 }
253
254 void CYClause::Output(CYOutput &out) const {
255 out << '\t';
256 if (value_ != NULL)
257 out << "case" << ' ' << *value_;
258 else
259 out << "default";
260 out << ':' << '\n';
261 ++out.indent_;
262 out << code_;
263 --out.indent_;
264 out << next_;
265 }
266
267 void CYDebugger::Output(CYOutput &out, CYFlags flags) const {
268 out << "debugger" << ';';
269 }
270
271 void CYBinding::Output(CYOutput &out, CYFlags flags) const {
272 out << *identifier_;
273 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
274 if (initializer_ != NULL) {
275 out << ' ' << '=' << ' ';
276 initializer_->Output(out, CYAssign::Precedence_, CYRight(flags));
277 }
278 }
279
280 void CYBindings::Output(CYOutput &out) const {
281 Output(out, CYNoFlags);
282 }
283
284 void CYBindings::Output(CYOutput &out, CYFlags flags) const {
285 const CYBindings *binding(this);
286 bool first(true);
287
288 for (;;) {
289 CYBindings *next(binding->next_);
290
291 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
292 first = false;
293 binding->binding_->Output(out, jacks);
294
295 if (next == NULL)
296 break;
297
298 out << ',' << ' ';
299 binding = next;
300 }
301 }
302
303 void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
304 object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger);
305 if (const char *word = property_->Word())
306 out << '.' << word;
307 else
308 out << '[' << *property_ << ']';
309 }
310
311 void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
312 out << "do";
313
314 unsigned line(out.position_.line);
315 unsigned indent(out.indent_);
316 code_->Single(out, CYCenter(flags), CYCompactLong);
317
318 if (out.position_.line != line && out.recent_ == indent)
319 out << ' ';
320 else
321 out << '\n' << '\t';
322
323 out << "while" << ' ' << '(' << *test_ << ')';
324 }
325
326 void CYElementSpread::Output(CYOutput &out) const {
327 out << "..." << value_;
328 }
329
330 void CYElementValue::Output(CYOutput &out) const {
331 if (value_ != NULL)
332 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
333 if (next_ != NULL || value_ == NULL) {
334 out << ',';
335 if (next_ != NULL && !next_->Elision())
336 out << ' ';
337 }
338 if (next_ != NULL)
339 next_->Output(out);
340 }
341
342 void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
343 out.Terminate();
344 }
345
346 void CYEval::Output(CYOutput &out, CYFlags flags) const {
347 _assert(false);
348 }
349
350 void CYExpress::Output(CYOutput &out, CYFlags flags) const {
351 expression_->Output(out, flags | CYNoBFC);
352 out << ';';
353 }
354
355 void CYExpression::Output(CYOutput &out) const {
356 Output(out, CYNoFlags);
357 }
358
359 void CYExpression::Output(CYOutput &out, int precedence, CYFlags flags) const {
360 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
361 out << '(' << *this << ')';
362 else
363 Output(out, flags);
364 }
365
366 void CYExternal::Output(CYOutput &out, CYFlags flags) const {
367 out << "extern" << abi_ << typed_;
368 out.Terminate();
369 }
370
371 void CYFatArrow::Output(CYOutput &out, CYFlags flags) const {
372 out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << '{' << code_ << '}';
373 }
374
375 void CYFinally::Output(CYOutput &out) const {
376 out << ' ' << "finally" << ' ';
377 out << '{' << '\n';
378 ++out.indent_;
379 out << code_;
380 --out.indent_;
381 out << '\t' << '}';
382 }
383
384 void CYFor::Output(CYOutput &out, CYFlags flags) const {
385 out << "for" << ' ' << '(';
386 if (initializer_ != NULL)
387 initializer_->Output(out, CYNoIn);
388 out.Terminate();
389 if (test_ != NULL)
390 out << ' ';
391 out << test_;
392 out.Terminate();
393 if (increment_ != NULL)
394 out << ' ';
395 out << increment_;
396 out << ')';
397 code_->Single(out, CYRight(flags), CYCompactShort);
398 }
399
400 void CYForLexical::Output(CYOutput &out, CYFlags flags) const {
401 out << (constant_ ? "const" : "let") << ' ';
402 binding_->Output(out, CYRight(flags));
403 }
404
405 void CYForIn::Output(CYOutput &out, CYFlags flags) const {
406 out << "for" << ' ' << '(';
407 initializer_->Output(out, CYNoIn | CYNoRightHand);
408 out << ' ' << "in" << ' ' << *iterable_ << ')';
409 code_->Single(out, CYRight(flags), CYCompactShort);
410 }
411
412 void CYForInitialized::Output(CYOutput &out, CYFlags flags) const {
413 out << "for" << ' ' << '(' << "var" << ' ';
414 binding_->Output(out, CYNoIn | CYNoRightHand);
415 out << ' ' << "in" << ' ' << *iterable_ << ')';
416 code_->Single(out, CYRight(flags), CYCompactShort);
417 }
418
419 void CYForInComprehension::Output(CYOutput &out) const {
420 out << "for" << ' ' << '(';
421 binding_->Output(out, CYNoIn | CYNoRightHand);
422 out << ' ' << "in" << ' ' << *iterable_ << ')';
423 }
424
425 void CYForOf::Output(CYOutput &out, CYFlags flags) const {
426 out << "for" << ' ' << '(';
427 initializer_->Output(out, CYNoRightHand);
428 out << ' ' << "of" << ' ' << *iterable_ << ')';
429 code_->Single(out, CYRight(flags), CYCompactShort);
430 }
431
432 void CYForOfComprehension::Output(CYOutput &out) const {
433 out << "for" << ' ' << '(';
434 binding_->Output(out, CYNoRightHand);
435 out << ' ' << "of" << ' ' << *iterable_ << ')' << next_;
436 }
437
438 void CYForVariable::Output(CYOutput &out, CYFlags flags) const {
439 out << "var" << ' ';
440 binding_->Output(out, CYRight(flags));
441 }
442
443 void CYFunction::Output(CYOutput &out) const {
444 out << '(' << parameters_ << ')' << ' ';
445 out << '{' << '\n';
446 ++out.indent_;
447 out << code_;
448 --out.indent_;
449 out << '\t' << '}';
450 }
451
452 void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
453 // XXX: one could imagine using + here to save a byte
454 bool protect((flags & CYNoFunction) != 0);
455 if (protect)
456 out << '(';
457 out << "function";
458 if (name_ != NULL)
459 out << ' ' << *name_;
460 CYFunction::Output(out);
461 if (protect)
462 out << ')';
463 }
464
465 void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
466 out << "function" << ' ' << *name_;
467 CYFunction::Output(out);
468 }
469
470 void CYFunctionParameter::Output(CYOutput &out) const {
471 binding_->Output(out, CYNoFlags);
472 if (next_ != NULL)
473 out << ',' << ' ' << *next_;
474 }
475
476 const char *CYIdentifier::Word() const {
477 return next_ == NULL || next_ == this ? CYWord::Word() : next_->Word();
478 }
479
480 void CYIf::Output(CYOutput &out, CYFlags flags) const {
481 bool protect(false);
482 if (false_ == NULL && (flags & CYNoDangle) != 0) {
483 protect = true;
484 out << '{';
485 }
486
487 out << "if" << ' ' << '(' << *test_ << ')';
488
489 CYFlags right(protect ? CYNoFlags : CYRight(flags));
490
491 CYFlags jacks(CYNoDangle);
492 if (false_ == NULL)
493 jacks |= right;
494 else
495 jacks |= protect ? CYNoFlags : CYCenter(flags);
496
497 unsigned line(out.position_.line);
498 unsigned indent(out.indent_);
499 true_->Single(out, jacks, CYCompactShort);
500
501 if (false_ != NULL) {
502 if (out.position_.line != line && out.recent_ == indent)
503 out << ' ';
504 else
505 out << '\n' << '\t';
506
507 out << "else";
508 false_->Single(out, right, CYCompactLong);
509 }
510
511 if (protect)
512 out << '}';
513 }
514
515 void CYIfComprehension::Output(CYOutput &out) const {
516 out << "if" << ' ' << '(' << *test_ << ')' << next_;
517 }
518
519 void CYImport::Output(CYOutput &out, CYFlags flags) const {
520 out << "@import";
521 }
522
523 void CYImportDeclaration::Output(CYOutput &out, CYFlags flags) const {
524 _assert(false);
525 }
526
527 void CYIndirect::Output(CYOutput &out, CYFlags flags) const {
528 out << "*";
529 rhs_->Output(out, Precedence(), CYRight(flags));
530 }
531
532 void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
533 object_->Output(out, Precedence(), CYLeft(flags));
534 if (const char *word = property_->Word())
535 out << "->" << word;
536 else
537 out << "->" << '[' << *property_ << ']';
538 }
539
540 void CYInfix::Output(CYOutput &out, CYFlags flags) const {
541 const char *name(Operator());
542 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
543 if (protect)
544 out << '(';
545 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
546 lhs_->Output(out, Precedence(), left);
547 out << ' ' << name << ' ';
548 CYFlags right(protect ? CYNoFlags : CYRight(flags));
549 rhs_->Output(out, Precedence() - 1, right);
550 if (protect)
551 out << ')';
552 }
553
554 void CYLabel::Output(CYOutput &out, CYFlags flags) const {
555 out << *name_ << ':';
556 statement_->Single(out, CYRight(flags), CYCompactShort);
557 }
558
559 void CYParenthetical::Output(CYOutput &out, CYFlags flags) const {
560 out << '(';
561 expression_->Output(out, CYCompound::Precedence_, CYNoFlags);
562 out << ')';
563 }
564
565 void CYStatement::Output(CYOutput &out) const {
566 Multiple(out);
567 }
568
569 void CYTemplate::Output(CYOutput &out, CYFlags flags) const {
570 _assert(false);
571 }
572
573 void CYTypeArrayOf::Output(CYOutput &out, CYIdentifier *identifier) const {
574 next_->Output(out, Precedence(), identifier);
575 out << '[';
576 out << size_;
577 out << ']';
578 }
579
580 void CYTypeBlockWith::Output(CYOutput &out, CYIdentifier *identifier) const {
581 out << '(' << '^';
582 next_->Output(out, Precedence(), identifier);
583 out << ')' << '(' << parameters_ << ')';
584 }
585
586 void CYTypeConstant::Output(CYOutput &out, CYIdentifier *identifier) const {
587 out << "const" << ' ';
588 next_->Output(out, Precedence(), identifier);
589 }
590
591 void CYTypeFunctionWith::Output(CYOutput &out, CYIdentifier *identifier) const {
592 next_->Output(out, Precedence(), identifier);
593 out << '(' << parameters_ << ')';
594 }
595
596 void CYTypePointerTo::Output(CYOutput &out, CYIdentifier *identifier) const {
597 out << '*';
598 next_->Output(out, Precedence(), identifier);
599 }
600
601 void CYTypeVolatile::Output(CYOutput &out, CYIdentifier *identifier) const {
602 out << "volatile";
603 next_->Output(out, Precedence(), identifier);
604 }
605
606 void CYTypeModifier::Output(CYOutput &out, int precedence, CYIdentifier *identifier) const {
607 if (this == NULL) {
608 out << identifier;
609 return;
610 }
611
612 bool protect(precedence > Precedence());
613
614 if (protect)
615 out << '(';
616 Output(out, identifier);
617 if (protect)
618 out << ')';
619 }
620
621 void CYTypedIdentifier::Output(CYOutput &out) const {
622 specifier_->Output(out);
623 modifier_->Output(out, 0, identifier_);
624 }
625
626 void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
627 out << "@encode(" << typed_ << ")";
628 }
629
630 void CYTypedParameter::Output(CYOutput &out) const {
631 out << typed_;
632 if (next_ != NULL)
633 out << ',' << ' ' << next_;
634 }
635
636 void CYLambda::Output(CYOutput &out, CYFlags flags) const {
637 // XXX: this is seriously wrong
638 out << "[](";
639 out << ")->";
640 out << "{";
641 out << "}";
642 }
643
644 void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
645 out << "typedef" << ' ' << *typed_;
646 out.Terminate();
647 }
648
649 void CYTypeExpression::Output(CYOutput &out, CYFlags flags) const {
650 out << '(' << "typedef" << ' ' << *typed_ << ')';
651 }
652
653 void CYLexical::Output(CYOutput &out, CYFlags flags) const {
654 out << "let" << ' ';
655 bindings_->Output(out, flags); // XXX: flags
656 out << ';';
657 }
658
659 void CYModule::Output(CYOutput &out) const {
660 out << part_;
661 if (next_ != NULL)
662 out << '.' << next_;
663 }
664
665 namespace cy {
666 namespace Syntax {
667
668 void New::Output(CYOutput &out, CYFlags flags) const {
669 out << "new" << ' ';
670 CYFlags jacks(CYNoCall | CYCenter(flags));
671 constructor_->Output(out, Precedence(), jacks);
672 if (arguments_ != NULL)
673 out << '(' << *arguments_ << ')';
674 }
675
676 } }
677
678 void CYNull::Output(CYOutput &out, CYFlags flags) const {
679 out << "null";
680 }
681
682 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
683 std::ostringstream str;
684 CYNumerify(str, Value());
685 std::string value(str.str());
686 out << value.c_str();
687 // XXX: this should probably also handle hex conversions and exponents
688 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
689 out << '.';
690 }
691
692 void CYNumber::PropertyName(CYOutput &out) const {
693 Output(out, CYNoFlags);
694 }
695
696 void CYObject::Output(CYOutput &out, CYFlags flags) const {
697 bool protect((flags & CYNoBrace) != 0);
698 if (protect)
699 out << '(';
700 out << '{' << '\n';
701 ++out.indent_;
702 out << properties_;
703 --out.indent_;
704 out << '\t' << '}';
705 if (protect)
706 out << ')';
707 }
708
709 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
710 lhs_->Output(out, Precedence(), CYLeft(flags));
711 out << Operator();
712 }
713
714 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
715 const char *name(Operator());
716 out << name;
717 if (Alphabetic())
718 out << ' ';
719 rhs_->Output(out, Precedence(), CYRight(flags));
720 }
721
722 void CYScript::Output(CYOutput &out) const {
723 out << code_;
724 }
725
726 void CYProperty::Output(CYOutput &out) const {
727 if (next_ != NULL || out.pretty_)
728 out << ',';
729 out << '\n' << next_;
730 }
731
732 void CYPropertyGetter::Output(CYOutput &out) const {
733 out << "get" << ' ';
734 name_->PropertyName(out);
735 CYFunction::Output(out);
736 CYProperty::Output(out);
737 }
738
739 void CYPropertyMethod::Output(CYOutput &out) const {
740 name_->PropertyName(out);
741 CYFunction::Output(out);
742 CYProperty::Output(out);
743 }
744
745 void CYPropertySetter::Output(CYOutput &out) const {
746 out << "set" << ' ';
747 name_->PropertyName(out);
748 CYFunction::Output(out);
749 CYProperty::Output(out);
750 }
751
752 void CYPropertyValue::Output(CYOutput &out) const {
753 out << '\t';
754 name_->PropertyName(out);
755 out << ':' << ' ';
756 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
757 CYProperty::Output(out);
758 }
759
760 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
761 out << Value();
762 }
763
764 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
765 out << "return";
766 if (value_ != NULL)
767 out << ' ' << *value_;
768 out << ';';
769 }
770
771 void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
772 call_->Output(out, CYLeft(flags));
773 out << ' ';
774 proc_->Output(out, CYRight(flags));
775 }
776
777 void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
778 out << '{' << ' ' << '|' << parameters_ << '|' << '\n';
779 ++out.indent_;
780 out << code_;
781 --out.indent_;
782 out << '\t' << '}';
783 }
784
785 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
786 bool first(true);
787 CYForEach (next, this) {
788 bool last(next->next_ == NULL);
789 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
790 first = false;
791 out << '\t';
792 next->Output(out, jacks);
793 out << '\n';
794 }
795 }
796
797 void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) const {
798 if (this == NULL)
799 return out.Terminate();
800
801 _assert(next_ == NULL);
802
803 CYCompactType compact(Compact());
804
805 if (compact >= request)
806 out << ' ';
807 else {
808 out << '\n';
809 ++out.indent_;
810 out << '\t';
811 }
812
813 Output(out, flags);
814
815 if (compact < request)
816 --out.indent_;
817 }
818
819 void CYString::Output(CYOutput &out, CYFlags flags) const {
820 std::ostringstream str;
821 CYStringify(str, value_, size_);
822 out << str.str().c_str();
823 }
824
825 void CYString::PropertyName(CYOutput &out) const {
826 if (const char *word = Word())
827 out << word;
828 else
829 out << *this;
830 }
831
832 static const char *Reserved_[] = {
833 "false", "null", "true",
834
835 "break", "case", "catch", "continue", "default",
836 "delete", "do", "else", "finally", "for", "function",
837 "if", "in", "instanceof", "new", "return", "switch",
838 "this", "throw", "try", "typeof", "var", "void",
839 "while", "with",
840
841 "debugger", "const",
842
843 "class", "enum", "export", "extends", "import", "super",
844
845 "abstract", "boolean", "byte", "char", "double", "final",
846 "float", "goto", "int", "long", "native", "short",
847 "synchronized", "throws", "transient", "volatile",
848
849 "let", "yield",
850
851 NULL
852 };
853
854 const char *CYString::Word() const {
855 if (size_ == 0 || !WordStartRange_[value_[0]])
856 return NULL;
857 for (size_t i(1); i != size_; ++i)
858 if (!WordEndRange_[value_[i]])
859 return NULL;
860 const char *value(Value());
861 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
862 if (strcmp(*reserved, value) == 0)
863 return NULL;
864 return value;
865 }
866
867 void CYSuperAccess::Output(CYOutput &out, CYFlags flags) const {
868 out << "super";
869 if (const char *word = property_->Word())
870 out << '.' << word;
871 else
872 out << '[' << *property_ << ']';
873 }
874
875 void CYSuperCall::Output(CYOutput &out, CYFlags flags) const {
876 out << "super" << '(' << arguments_ << ')';
877 }
878
879 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
880 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{' << '\n';
881 ++out.indent_;
882 out << clauses_;
883 --out.indent_;
884 out << '\t' << '}';
885 }
886
887 void CYThis::Output(CYOutput &out, CYFlags flags) const {
888 out << "this";
889 }
890
891 namespace cy {
892 namespace Syntax {
893
894 void Throw::Output(CYOutput &out, CYFlags flags) const {
895 out << "throw";
896 if (value_ != NULL)
897 out << ' ' << *value_;
898 out << ';';
899 }
900
901 void Try::Output(CYOutput &out, CYFlags flags) const {
902 out << "try" << ' ';
903 out << '{' << '\n';
904 ++out.indent_;
905 out << code_;
906 --out.indent_;
907 out << '\t' << '}';
908 out << catch_ << finally_;
909 }
910
911 } }
912
913 void CYTypeError::Output(CYOutput &out) const {
914 out << "@error";
915 }
916
917 void CYTypeLong::Output(CYOutput &out) const {
918 out << "long" << specifier_;
919 }
920
921 void CYTypeShort::Output(CYOutput &out) const {
922 out << "short" << specifier_;
923 }
924
925 void CYTypeSigned::Output(CYOutput &out) const {
926 out << "signed" << specifier_;
927 }
928
929 void CYTypeStruct::Output(CYOutput &out) const {
930 out << "struct" << ' ';
931 if (name_ != NULL)
932 out << *name_ << ' ';
933 out << '{' << '\n';
934 ++out.indent_;
935 CYForEach (field, fields_) {
936 out << '\t' << *field->typed_;
937 out.Terminate();
938 out << '\n';
939 }
940 --out.indent_;
941 out << '}';
942 }
943
944 void CYTypeUnsigned::Output(CYOutput &out) const {
945 out << "unsigned" << specifier_;
946 }
947
948 void CYTypeVariable::Output(CYOutput &out) const {
949 out << *name_;
950 }
951
952 void CYTypeVoid::Output(CYOutput &out) const {
953 out << "void";
954 }
955
956 void CYVar::Output(CYOutput &out, CYFlags flags) const {
957 out << "var" << ' ';
958 bindings_->Output(out, flags); // XXX: flags
959 out << ';';
960 }
961
962 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
963 out << *name_;
964 }
965
966 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
967 out << "while" << ' ' << '(' << *test_ << ')';
968 code_->Single(out, CYRight(flags), CYCompactShort);
969 }
970
971 void CYWith::Output(CYOutput &out, CYFlags flags) const {
972 out << "with" << ' ' << '(' << *scope_ << ')';
973 code_->Single(out, CYRight(flags), CYCompactShort);
974 }
975
976 void CYWord::Output(CYOutput &out) const {
977 out << Word();
978 if (out.options_.verbose_) {
979 out('@');
980 char number[32];
981 sprintf(number, "%p", this);
982 out(number);
983 }
984 }
985
986 void CYWord::PropertyName(CYOutput &out) const {
987 Output(out);
988 }
989
990 const char *CYWord::Word() const {
991 return word_;
992 }