]> git.saurik.com Git - cycript.git/blob - Output.cpp
Hold JavaRef<jstring> throughout CYJavaUTF8String.
[cycript.git] / Output.cpp
1 /* Cycript - The Truly Universal Scripting Language
2 * Copyright (C) 2009-2016 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <cmath>
23 #include <iomanip>
24 #include <sstream>
25
26 #include "Syntax.hpp"
27
28 enum CYStringType {
29 CYStringTypeSingle,
30 CYStringTypeDouble,
31 CYStringTypeTemplate,
32 };
33
34 void CYStringify(std::ostringstream &str, const char *data, size_t size, CYStringifyMode mode) {
35 if (size == 0) {
36 str << "\"\"";
37 return;
38 }
39
40 unsigned quot(0), apos(0), tick(0), line(0);
41 for (const char *value(data), *end(data + size); value != end; ++value)
42 switch (*value) {
43 case '"': ++quot; break;
44 case '\'': ++apos; break;
45 case '`': ++tick; break;
46 case '$': ++tick; break;
47 case '\n': ++line; break;
48 }
49
50 bool split;
51 if (mode != CYStringifyModeCycript)
52 split = false;
53 else {
54 double ratio(double(line) / size);
55 split = size > 10 && line > 2 && ratio > 0.005 && ratio < 0.10;
56 }
57
58 CYStringType type;
59 if (mode == CYStringifyModeNative)
60 type = CYStringTypeDouble;
61 else if (split)
62 type = CYStringTypeTemplate;
63 else if (quot > apos)
64 type = CYStringTypeSingle;
65 else
66 type = CYStringTypeDouble;
67
68 bool parens(split && mode != CYStringifyModeNative && type != CYStringTypeTemplate);
69 if (parens)
70 str << '(';
71
72 char border;
73 switch (type) {
74 case CYStringTypeSingle: border = '\''; break;
75 case CYStringTypeDouble: border = '"'; break;
76 case CYStringTypeTemplate: border = '`'; break;
77 }
78
79 str << border;
80
81 bool space(false);
82
83 for (const char *value(data), *end(data + size); value != end; ++value)
84 if (*value == ' ') {
85 space = true;
86 str << ' ';
87 } else { switch (uint8_t next = *value) {
88 case '\\': str << "\\\\"; break;
89 case '\b': str << "\\b"; break;
90 case '\f': str << "\\f"; break;
91 case '\r': str << "\\r"; break;
92 case '\t': str << "\\t"; break;
93 case '\v': str << "\\v"; break;
94
95 case '\a':
96 if (mode == CYStringifyModeNative)
97 str << "\\a";
98 else goto simple;
99 break;
100
101 case '\n':
102 if (!split)
103 str << "\\n";
104 /*else if (mode == CYStringifyModeNative)
105 str << border << "\\\n" << border;*/
106 else if (type != CYStringTypeTemplate)
107 str << border << '+' << border;
108 else if (!space)
109 str << '\n';
110 else
111 str << "\\n\\\n";
112 break;
113
114 case '$':
115 if (type == CYStringTypeTemplate)
116 str << "\\$";
117 else goto simple;
118 break;
119
120 case '`':
121 if (type == CYStringTypeTemplate)
122 str << "\\`";
123 else goto simple;
124 break;
125
126 case '"':
127 if (type == CYStringTypeDouble)
128 str << "\\\"";
129 else goto simple;
130 break;
131
132 case '\'':
133 if (type == CYStringTypeSingle)
134 str << "\\'";
135 else goto simple;
136 break;
137
138 case '\0':
139 if (mode != CYStringifyModeNative && value[1] >= '0' && value[1] <= '9')
140 str << "\\x00";
141 else
142 str << "\\0";
143 break;
144
145 default:
146 if (next >= 0x20 && next < 0x7f) simple:
147 str << *value;
148 else if (mode == CYStringifyModeNative)
149 str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(*value & 0xff);
150 else {
151 unsigned levels(1);
152 if ((next & 0x80) != 0)
153 while ((next & 0x80 >> ++levels) != 0);
154
155 unsigned point(next & 0xff >> levels);
156 while (--levels != 0)
157 point = point << 6 | uint8_t(*++value) & 0x3f;
158
159 if (point < 0x100)
160 str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << point;
161 else if (point < 0x10000)
162 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << point;
163 else {
164 point -= 0x10000;
165 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xd800 | point >> 0x0a);
166 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xdc00 | point & 0x3ff);
167 }
168 }
169 } space = false; }
170
171 str << border;
172
173 if (parens)
174 str << ')';
175 }
176
177 void CYNumerify(std::ostringstream &str, double value) {
178 if (std::isinf(value)) {
179 if (value < 0)
180 str << '-';
181 str << "Infinity";
182 return;
183 }
184
185 char string[32];
186 // XXX: I want this to print 1e3 rather than 1000
187 sprintf(string, "%.17g", value);
188 str << string;
189 }
190
191 void CYOutput::Terminate() {
192 operator ()(';');
193 mode_ = NoMode;
194 }
195
196 CYOutput &CYOutput::operator <<(char rhs) {
197 if (rhs == ' ' || rhs == '\n')
198 if (pretty_)
199 operator ()(rhs);
200 else goto done;
201 else if (rhs == '\t')
202 if (pretty_)
203 for (unsigned i(0); i != indent_; ++i)
204 operator ()(" ", 4);
205 else goto done;
206 else if (rhs == '\r') {
207 if (right_) {
208 operator ()('\n');
209 right_ = false;
210 } goto done;
211 } else goto work;
212
213 right_ = true;
214 mode_ = NoMode;
215 goto done;
216
217 work:
218 if (mode_ == Terminated && rhs != '}') {
219 right_ = true;
220 operator ()(';');
221 }
222
223 if (rhs == ';') {
224 if (pretty_)
225 goto none;
226 else {
227 mode_ = Terminated;
228 goto done;
229 }
230 } else if (rhs == '+') {
231 if (mode_ == NoPlus)
232 operator ()(' ');
233 mode_ = NoPlus;
234 } else if (rhs == '-') {
235 if (mode_ == NoHyphen)
236 operator ()(' ');
237 mode_ = NoHyphen;
238 } else if (WordEndRange_[rhs]) {
239 if (mode_ == NoLetter)
240 operator ()(' ');
241 mode_ = NoLetter;
242 } else none:
243 mode_ = NoMode;
244
245 right_ = true;
246 operator ()(rhs);
247 done:
248 return *this;
249 }
250
251 CYOutput &CYOutput::operator <<(const char *rhs) {
252 size_t size(strlen(rhs));
253
254 if (size == 1)
255 return *this << *rhs;
256
257 if (mode_ == Terminated)
258 operator ()(';');
259 else if (
260 mode_ == NoPlus && *rhs == '+' ||
261 mode_ == NoHyphen && *rhs == '-' ||
262 mode_ == NoLetter && WordEndRange_[*rhs]
263 )
264 operator ()(' ');
265
266 char last(rhs[size - 1]);
267 if (WordEndRange_[last] || last == '/')
268 mode_ = NoLetter;
269 else
270 mode_ = NoMode;
271
272 right_ = true;
273 operator ()(rhs, size);
274 return *this;
275 }
276
277 void CYArgument::Output(CYOutput &out) const {
278 if (name_ != NULL) {
279 out << *name_;
280 if (value_ != NULL)
281 out << ':' << ' ';
282 }
283 if (value_ != NULL)
284 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
285 if (next_ != NULL) {
286 out << ',';
287 out << ' ' << *next_;
288 }
289 }
290
291 void CYArray::Output(CYOutput &out, CYFlags flags) const {
292 out << '[' << elements_ << ']';
293 }
294
295 void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
296 out << '[' << *expression_ << ' ' << *comprehensions_ << ']';
297 }
298
299 void CYAssignment::Output(CYOutput &out, CYFlags flags) const {
300 lhs_->Output(out, Precedence() - 1, CYLeft(flags) | CYNoRightHand);
301 out << ' ' << Operator() << ' ';
302 rhs_->Output(out, Precedence(), CYRight(flags));
303 }
304
305 void CYAttemptMember::Output(CYOutput &out, CYFlags flags) const {
306 object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger);
307 if (const char *word = property_->Word())
308 out << "?." << word;
309 else
310 _assert(false);
311 }
312
313 void CYBlock::Output(CYOutput &out, CYFlags flags) const {
314 out << '{' << '\n';
315 ++out.indent_;
316 out << code_;
317 --out.indent_;
318 out << '\t' << '}';
319 }
320
321 void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
322 out << '!' << (Value() ? "0" : "1");
323 if ((flags & CYNoInteger) != 0)
324 out << '.';
325 }
326
327 void CYBreak::Output(CYOutput &out, CYFlags flags) const {
328 out << "break";
329 if (label_ != NULL)
330 out << ' ' << *label_;
331 out << ';';
332 }
333
334 void CYCall::Output(CYOutput &out, CYFlags flags) const {
335 bool protect((flags & CYNoCall) != 0);
336 if (protect)
337 out << '(';
338 function_->Output(out, Precedence(), protect ? CYNoFlags : flags);
339 out << '(' << arguments_ << ')';
340 if (protect)
341 out << ')';
342 }
343
344 namespace cy {
345 namespace Syntax {
346
347 void Catch::Output(CYOutput &out) const {
348 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ';
349 out << '{' << '\n';
350 ++out.indent_;
351 out << code_;
352 --out.indent_;
353 out << '\t' << '}';
354 }
355
356 } }
357
358 void CYClassExpression::Output(CYOutput &out, CYFlags flags) const {
359 bool protect((flags & CYNoClass) != 0);
360 if (protect)
361 out << '(';
362 out << "class";
363 if (name_ != NULL)
364 out << ' ' << *name_;
365 out << *tail_;;
366 if (protect)
367 out << ')';
368 }
369
370 void CYClassStatement::Output(CYOutput &out, CYFlags flags) const {
371 out << "class" << ' ' << *name_ << *tail_;
372 }
373
374 void CYClassTail::Output(CYOutput &out) const {
375 if (extends_ == NULL)
376 out << ' ';
377 else {
378 out << '\n';
379 ++out.indent_;
380 out << "extends" << ' ';
381 extends_->Output(out, CYAssign::Precedence_ - 1, CYNoFlags);
382 out << '\n';
383 --out.indent_;
384 }
385
386 out << '{' << '\n';
387 ++out.indent_;
388
389 --out.indent_;
390 out << '}';
391 }
392
393 void CYCompound::Output(CYOutput &out, CYFlags flags) const {
394 if (next_ == NULL)
395 expression_->Output(out, flags);
396 else {
397 expression_->Output(out, CYLeft(flags));
398 out << ',' << ' ';
399 next_->Output(out, CYRight(flags));
400 }
401 }
402
403 void CYComputed::PropertyName(CYOutput &out) const {
404 out << '[';
405 expression_->Output(out, CYAssign::Precedence_, CYNoFlags);
406 out << ']';
407 }
408
409 void CYCondition::Output(CYOutput &out, CYFlags flags) const {
410 test_->Output(out, Precedence() - 1, CYLeft(flags));
411 out << ' ' << '?' << ' ';
412 if (true_ != NULL)
413 true_->Output(out, CYAssign::Precedence_, CYNoColon);
414 out << ' ' << ':' << ' ';
415 false_->Output(out, CYAssign::Precedence_, CYRight(flags));
416 }
417
418 void CYContinue::Output(CYOutput &out, CYFlags flags) const {
419 out << "continue";
420 if (label_ != NULL)
421 out << ' ' << *label_;
422 out << ';';
423 }
424
425 void CYClause::Output(CYOutput &out) const {
426 out << '\t';
427 if (value_ == NULL)
428 out << "default";
429 else {
430 out << "case" << ' ';
431 value_->Output(out, CYNoColon);
432 }
433 out << ':' << '\n';
434 ++out.indent_;
435 out << code_;
436 --out.indent_;
437 out << next_;
438 }
439
440 void CYDebugger::Output(CYOutput &out, CYFlags flags) const {
441 out << "debugger" << ';';
442 }
443
444 void CYBinding::Output(CYOutput &out, CYFlags flags) const {
445 out << *identifier_;
446 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
447 if (initializer_ != NULL) {
448 out << ' ' << '=' << ' ';
449 initializer_->Output(out, CYAssign::Precedence_, CYRight(flags));
450 }
451 }
452
453 void CYBindings::Output(CYOutput &out) const {
454 Output(out, CYNoFlags);
455 }
456
457 void CYBindings::Output(CYOutput &out, CYFlags flags) const {
458 const CYBindings *binding(this);
459 bool first(true);
460
461 for (;;) {
462 CYBindings *next(binding->next_);
463
464 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
465 first = false;
466 binding->binding_->Output(out, jacks);
467
468 if (next == NULL)
469 break;
470
471 out << ',' << ' ';
472 binding = next;
473 }
474 }
475
476 void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
477 object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger);
478 if (const char *word = property_->Word())
479 out << '.' << word;
480 else
481 out << '[' << *property_ << ']';
482 }
483
484 void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
485 out << "do";
486
487 unsigned line(out.position_.line);
488 unsigned indent(out.indent_);
489 code_->Single(out, CYCenter(flags), CYCompactLong);
490
491 if (out.position_.line != line && out.recent_ == indent)
492 out << ' ';
493 else
494 out << '\n' << '\t';
495
496 out << "while" << ' ' << '(' << *test_ << ')';
497 }
498
499 void CYElementSpread::Output(CYOutput &out) const {
500 out << "..." << value_;
501 }
502
503 void CYElementValue::Output(CYOutput &out) const {
504 if (value_ != NULL)
505 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
506 if (next_ != NULL || value_ == NULL) {
507 out << ',';
508 if (next_ != NULL && !next_->Elision())
509 out << ' ';
510 }
511 if (next_ != NULL)
512 next_->Output(out);
513 }
514
515 void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
516 out.Terminate();
517 }
518
519 void CYEval::Output(CYOutput &out, CYFlags flags) const {
520 _assert(false);
521 }
522
523 void CYExpress::Output(CYOutput &out, CYFlags flags) const {
524 expression_->Output(out, flags | CYNoBFC);
525 out << ';';
526 }
527
528 void CYExpression::Output(CYOutput &out) const {
529 Output(out, CYNoFlags);
530 }
531
532 void CYExpression::Output(CYOutput &out, int precedence, CYFlags flags) const {
533 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
534 out << '(' << *this << ')';
535 else
536 Output(out, flags);
537 }
538
539 void CYExtend::Output(CYOutput &out, CYFlags flags) const {
540 lhs_->Output(out, CYLeft(flags));
541 out << ' ' << object_;
542 }
543
544 void CYExternalDefinition::Output(CYOutput &out, CYFlags flags) const {
545 out << "extern" << ' ' << abi_ << ' ';
546 type_->Output(out, name_);
547 out.Terminate();
548 }
549
550 void CYExternalExpression::Output(CYOutput &out, CYFlags flags) const {
551 out << '(' << "extern" << ' ' << abi_ << ' ';
552 type_->Output(out, name_);
553 out << ')';
554 }
555
556 void CYFatArrow::Output(CYOutput &out, CYFlags flags) const {
557 out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << '{' << code_ << '}';
558 }
559
560 void CYFinally::Output(CYOutput &out) const {
561 out << ' ' << "finally" << ' ';
562 out << '{' << '\n';
563 ++out.indent_;
564 out << code_;
565 --out.indent_;
566 out << '\t' << '}';
567 }
568
569 void CYFor::Output(CYOutput &out, CYFlags flags) const {
570 out << "for" << ' ' << '(';
571 if (initializer_ != NULL)
572 initializer_->Output(out, CYNoIn);
573 out.Terminate();
574 if (test_ != NULL)
575 out << ' ';
576 out << test_;
577 out.Terminate();
578 if (increment_ != NULL)
579 out << ' ';
580 out << increment_;
581 out << ')';
582 code_->Single(out, CYRight(flags), CYCompactShort);
583 }
584
585 void CYForLexical::Output(CYOutput &out, CYFlags flags) const {
586 out << (constant_ ? "const" : "let") << ' ';
587 binding_->Output(out, CYRight(flags));
588 }
589
590 void CYForIn::Output(CYOutput &out, CYFlags flags) const {
591 out << "for" << ' ' << '(';
592 initializer_->Output(out, CYNoIn | CYNoRightHand);
593 out << ' ' << "in" << ' ' << *iterable_ << ')';
594 code_->Single(out, CYRight(flags), CYCompactShort);
595 }
596
597 void CYForInitialized::Output(CYOutput &out, CYFlags flags) const {
598 out << "for" << ' ' << '(' << "var" << ' ';
599 binding_->Output(out, CYNoIn | CYNoRightHand);
600 out << ' ' << "in" << ' ' << *iterable_ << ')';
601 code_->Single(out, CYRight(flags), CYCompactShort);
602 }
603
604 void CYForInComprehension::Output(CYOutput &out) const {
605 out << "for" << ' ' << '(';
606 binding_->Output(out, CYNoIn | CYNoRightHand);
607 out << ' ' << "in" << ' ' << *iterable_ << ')';
608 }
609
610 void CYForOf::Output(CYOutput &out, CYFlags flags) const {
611 out << "for" << ' ' << '(';
612 initializer_->Output(out, CYNoRightHand);
613 out << ' ' << "of" << ' ' << *iterable_ << ')';
614 code_->Single(out, CYRight(flags), CYCompactShort);
615 }
616
617 void CYForOfComprehension::Output(CYOutput &out) const {
618 out << "for" << ' ' << '(';
619 binding_->Output(out, CYNoRightHand);
620 out << ' ' << "of" << ' ' << *iterable_ << ')' << next_;
621 }
622
623 void CYForVariable::Output(CYOutput &out, CYFlags flags) const {
624 out << "var" << ' ';
625 binding_->Output(out, CYRight(flags));
626 }
627
628 void CYFunction::Output(CYOutput &out) const {
629 out << '(' << parameters_ << ')' << ' ';
630 out << '{' << '\n';
631 ++out.indent_;
632 out << code_;
633 --out.indent_;
634 out << '\t' << '}';
635 }
636
637 void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
638 // XXX: one could imagine using + here to save a byte
639 bool protect((flags & CYNoFunction) != 0);
640 if (protect)
641 out << '(';
642 out << "function";
643 if (name_ != NULL)
644 out << ' ' << *name_;
645 CYFunction::Output(out);
646 if (protect)
647 out << ')';
648 }
649
650 void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
651 out << "function" << ' ' << *name_;
652 CYFunction::Output(out);
653 }
654
655 void CYFunctionParameter::Output(CYOutput &out) const {
656 binding_->Output(out, CYNoFlags);
657 if (next_ != NULL)
658 out << ',' << ' ' << *next_;
659 }
660
661 const char *CYIdentifier::Word() const {
662 return next_ == NULL || next_ == this ? CYWord::Word() : next_->Word();
663 }
664
665 void CYIf::Output(CYOutput &out, CYFlags flags) const {
666 bool protect(false);
667 if (false_ == NULL && (flags & CYNoDangle) != 0) {
668 protect = true;
669 out << '{';
670 }
671
672 out << "if" << ' ' << '(' << *test_ << ')';
673
674 CYFlags right(protect ? CYNoFlags : CYRight(flags));
675
676 CYFlags jacks(CYNoDangle);
677 if (false_ == NULL)
678 jacks |= right;
679 else
680 jacks |= protect ? CYNoFlags : CYCenter(flags);
681
682 unsigned line(out.position_.line);
683 unsigned indent(out.indent_);
684 true_->Single(out, jacks, CYCompactShort);
685
686 if (false_ != NULL) {
687 if (out.position_.line != line && out.recent_ == indent)
688 out << ' ';
689 else
690 out << '\n' << '\t';
691
692 out << "else";
693 false_->Single(out, right, CYCompactLong);
694 }
695
696 if (protect)
697 out << '}';
698 }
699
700 void CYIfComprehension::Output(CYOutput &out) const {
701 out << "if" << ' ' << '(' << *test_ << ')' << next_;
702 }
703
704 void CYImport::Output(CYOutput &out, CYFlags flags) const {
705 out << "@import";
706 }
707
708 void CYImportDeclaration::Output(CYOutput &out, CYFlags flags) const {
709 _assert(false);
710 }
711
712 void CYIndirect::Output(CYOutput &out, CYFlags flags) const {
713 out << "*";
714 rhs_->Output(out, Precedence(), CYRight(flags));
715 }
716
717 void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
718 object_->Output(out, Precedence(), CYLeft(flags));
719 if (const char *word = property_->Word())
720 out << "->" << word;
721 else
722 out << "->" << '[' << *property_ << ']';
723 }
724
725 void CYInfix::Output(CYOutput &out, CYFlags flags) const {
726 const char *name(Operator());
727 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
728 if (protect)
729 out << '(';
730 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
731 lhs_->Output(out, Precedence(), left);
732 out << ' ' << name << ' ';
733 CYFlags right(protect ? CYNoFlags : CYRight(flags));
734 rhs_->Output(out, Precedence() - 1, right);
735 if (protect)
736 out << ')';
737 }
738
739 void CYLabel::Output(CYOutput &out, CYFlags flags) const {
740 out << *name_ << ':';
741 statement_->Single(out, CYRight(flags), CYCompactShort);
742 }
743
744 void CYParenthetical::Output(CYOutput &out, CYFlags flags) const {
745 out << '(';
746 expression_->Output(out, CYCompound::Precedence_, CYNoFlags);
747 out << ')';
748 }
749
750 void CYStatement::Output(CYOutput &out) const {
751 Multiple(out);
752 }
753
754 void CYTemplate::Output(CYOutput &out, CYFlags flags) const {
755 _assert(false);
756 }
757
758 void CYTypeArrayOf::Output(CYOutput &out, CYPropertyName *name) const {
759 next_->Output(out, Precedence(), name, false);
760 out << '[';
761 out << size_;
762 out << ']';
763 }
764
765 void CYTypeBlockWith::Output(CYOutput &out, CYPropertyName *name) const {
766 out << '(' << '^';
767 next_->Output(out, Precedence(), name, false);
768 out << ')' << '(' << parameters_ << ')';
769 }
770
771 void CYTypeConstant::Output(CYOutput &out, CYPropertyName *name) const {
772 out << "const";
773 next_->Output(out, Precedence(), name, false);
774 }
775
776 void CYTypeFunctionWith::Output(CYOutput &out, CYPropertyName *name) const {
777 next_->Output(out, Precedence(), name, false);
778 out << '(' << parameters_;
779 if (variadic_) {
780 if (parameters_ != NULL)
781 out << ',' << ' ';
782 out << "...";
783 }
784 out << ')';
785 }
786
787 void CYTypePointerTo::Output(CYOutput &out, CYPropertyName *name) const {
788 out << '*';
789 next_->Output(out, Precedence(), name, false);
790 }
791
792 void CYTypeVolatile::Output(CYOutput &out, CYPropertyName *name) const {
793 out << "volatile";
794 next_->Output(out, Precedence(), name, true);
795 }
796
797 void CYTypeModifier::Output(CYOutput &out, int precedence, CYPropertyName *name, bool space) const {
798 if (this == NULL && name == NULL)
799 return;
800 else if (space)
801 out << ' ';
802
803 if (this == NULL) {
804 name->PropertyName(out);
805 return;
806 }
807
808 bool protect(precedence > Precedence());
809
810 if (protect)
811 out << '(';
812 Output(out, name);
813 if (protect)
814 out << ')';
815 }
816
817 void CYType::Output(CYOutput &out, CYPropertyName *name) const {
818 out << *specifier_;
819 modifier_->Output(out, 0, name, true);
820 }
821
822 void CYType::Output(CYOutput &out) const {
823 Output(out, NULL);
824 }
825
826 void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
827 out << "@encode(" << typed_ << ")";
828 }
829
830 void CYTypedParameter::Output(CYOutput &out) const {
831 type_->Output(out, name_);
832 if (next_ != NULL)
833 out << ',' << ' ' << next_;
834 }
835
836 void CYLambda::Output(CYOutput &out, CYFlags flags) const {
837 // XXX: this is seriously wrong
838 out << "[](";
839 out << ")->";
840 out << "{";
841 out << "}";
842 }
843
844 void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
845 out << "typedef" << ' ';
846 type_->Output(out, name_);
847 out.Terminate();
848 }
849
850 void CYTypeExpression::Output(CYOutput &out, CYFlags flags) const {
851 out << '(' << "typedef" << ' ' << *typed_ << ')';
852 }
853
854 void CYLexical::Output(CYOutput &out, CYFlags flags) const {
855 out << "let" << ' ';
856 bindings_->Output(out, flags); // XXX: flags
857 out << ';';
858 }
859
860 void CYModule::Output(CYOutput &out) const {
861 out << part_;
862 if (next_ != NULL)
863 out << '.' << next_;
864 }
865
866 namespace cy {
867 namespace Syntax {
868
869 void New::Output(CYOutput &out, CYFlags flags) const {
870 out << "new" << ' ';
871 CYFlags jacks(CYNoCall | CYCenter(flags));
872 constructor_->Output(out, Precedence(), jacks);
873 if (arguments_ != NULL)
874 out << '(' << *arguments_ << ')';
875 }
876
877 } }
878
879 void CYNull::Output(CYOutput &out, CYFlags flags) const {
880 out << "null";
881 }
882
883 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
884 std::ostringstream str;
885 CYNumerify(str, Value());
886 std::string value(str.str());
887 out << value.c_str();
888 // XXX: this should probably also handle hex conversions and exponents
889 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
890 out << '.';
891 }
892
893 void CYNumber::PropertyName(CYOutput &out) const {
894 Output(out, CYNoFlags);
895 }
896
897 void CYObject::Output(CYOutput &out, CYFlags flags) const {
898 bool protect((flags & CYNoBrace) != 0);
899 if (protect)
900 out << '(';
901 out << '{' << '\n';
902 ++out.indent_;
903 out << properties_;
904 --out.indent_;
905 out << '\t' << '}';
906 if (protect)
907 out << ')';
908 }
909
910 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
911 lhs_->Output(out, Precedence(), CYLeft(flags));
912 out << Operator();
913 }
914
915 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
916 const char *name(Operator());
917 out << name;
918 if (Alphabetic())
919 out << ' ';
920 rhs_->Output(out, Precedence(), CYRight(flags));
921 }
922
923 void CYScript::Output(CYOutput &out) const {
924 out << code_;
925 }
926
927 void CYProperty::Output(CYOutput &out) const {
928 if (next_ != NULL || out.pretty_)
929 out << ',';
930 out << '\n' << next_;
931 }
932
933 void CYPropertyGetter::Output(CYOutput &out) const {
934 out << "get" << ' ';
935 name_->PropertyName(out);
936 CYFunction::Output(out);
937 CYProperty::Output(out);
938 }
939
940 void CYPropertyMethod::Output(CYOutput &out) const {
941 name_->PropertyName(out);
942 CYFunction::Output(out);
943 CYProperty::Output(out);
944 }
945
946 void CYPropertySetter::Output(CYOutput &out) const {
947 out << "set" << ' ';
948 name_->PropertyName(out);
949 CYFunction::Output(out);
950 CYProperty::Output(out);
951 }
952
953 void CYPropertyValue::Output(CYOutput &out) const {
954 out << '\t';
955 name_->PropertyName(out);
956 out << ':' << ' ';
957 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
958 CYProperty::Output(out);
959 }
960
961 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
962 out << Value();
963 }
964
965 void CYResolveMember::Output(CYOutput &out, CYFlags flags) const {
966 object_->Output(out, Precedence(), CYLeft(flags));
967 if (const char *word = property_->Word())
968 out << "::" << word;
969 else
970 out << "::" << '[' << *property_ << ']';
971 }
972
973 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
974 out << "return";
975 if (value_ != NULL)
976 out << ' ' << *value_;
977 out << ';';
978 }
979
980 void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
981 lhs_->Output(out, CYLeft(flags));
982 out << ' ';
983 proc_->Output(out, CYRight(flags));
984 }
985
986 void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
987 out << '{' << ' ' << '|' << parameters_ << '|' << '\n';
988 ++out.indent_;
989 out << code_;
990 --out.indent_;
991 out << '\t' << '}';
992 }
993
994 void CYSubscriptMember::Output(CYOutput &out, CYFlags flags) const {
995 object_->Output(out, Precedence(), CYLeft(flags));
996 out << "." << '[' << *property_ << ']';
997 }
998
999 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
1000 bool first(true);
1001 CYForEach (next, this) {
1002 bool last(next->next_ == NULL);
1003 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
1004 first = false;
1005 out << '\t';
1006 next->Output(out, jacks);
1007 out << '\n';
1008 }
1009 }
1010
1011 void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) const {
1012 if (this == NULL)
1013 return out.Terminate();
1014
1015 _assert(next_ == NULL);
1016
1017 CYCompactType compact(Compact());
1018
1019 if (compact >= request)
1020 out << ' ';
1021 else {
1022 out << '\n';
1023 ++out.indent_;
1024 out << '\t';
1025 }
1026
1027 Output(out, flags);
1028
1029 if (compact < request)
1030 --out.indent_;
1031 }
1032
1033 void CYString::Output(CYOutput &out, CYFlags flags) const {
1034 std::ostringstream str;
1035 CYStringify(str, value_, size_, CYStringifyModeLegacy);
1036 out << str.str().c_str();
1037 }
1038
1039 void CYString::PropertyName(CYOutput &out) const {
1040 if (const char *word = Word())
1041 out << word;
1042 else
1043 out << *this;
1044 }
1045
1046 static const char *Reserved_[] = {
1047 "false", "null", "true",
1048
1049 "break", "case", "catch", "continue", "default",
1050 "delete", "do", "else", "finally", "for", "function",
1051 "if", "in", "instanceof", "new", "return", "switch",
1052 "this", "throw", "try", "typeof", "var", "void",
1053 "while", "with",
1054
1055 "debugger", "const",
1056
1057 "class", "enum", "export", "extends", "import", "super",
1058
1059 "abstract", "boolean", "byte", "char", "double", "final",
1060 "float", "goto", "int", "long", "native", "short",
1061 "synchronized", "throws", "transient", "volatile",
1062
1063 "let", "yield",
1064
1065 NULL
1066 };
1067
1068 const char *CYString::Word() const {
1069 if (size_ == 0 || !WordStartRange_[value_[0]])
1070 return NULL;
1071 for (size_t i(1); i != size_; ++i)
1072 if (!WordEndRange_[value_[i]])
1073 return NULL;
1074 const char *value(Value());
1075 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
1076 if (strcmp(*reserved, value) == 0)
1077 return NULL;
1078 return value;
1079 }
1080
1081 void CYStructDefinition::Output(CYOutput &out, CYFlags flags) const {
1082 out << "struct" << ' ' << *name_ << *tail_;
1083 }
1084
1085 void CYStructTail::Output(CYOutput &out) const {
1086 out << ' ' << '{' << '\n';
1087 ++out.indent_;
1088 CYForEach (field, fields_) {
1089 out << '\t';
1090 field->type_->Output(out, field->name_);
1091 out.Terminate();
1092 out << '\n';
1093 }
1094 --out.indent_;
1095 out << '\t' << '}';
1096 }
1097
1098 void CYSuperAccess::Output(CYOutput &out, CYFlags flags) const {
1099 out << "super";
1100 if (const char *word = property_->Word())
1101 out << '.' << word;
1102 else
1103 out << '[' << *property_ << ']';
1104 }
1105
1106 void CYSuperCall::Output(CYOutput &out, CYFlags flags) const {
1107 out << "super" << '(' << arguments_ << ')';
1108 }
1109
1110 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
1111 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{' << '\n';
1112 ++out.indent_;
1113 out << clauses_;
1114 --out.indent_;
1115 out << '\t' << '}';
1116 }
1117
1118 void CYSymbol::Output(CYOutput &out, CYFlags flags) const {
1119 bool protect((flags & CYNoColon) != 0);
1120 if (protect)
1121 out << '(';
1122 out << ':' << name_;
1123 if (protect)
1124 out << ')';
1125 }
1126
1127 void CYThis::Output(CYOutput &out, CYFlags flags) const {
1128 out << "this";
1129 }
1130
1131 namespace cy {
1132 namespace Syntax {
1133
1134 void Throw::Output(CYOutput &out, CYFlags flags) const {
1135 out << "throw";
1136 if (value_ != NULL)
1137 out << ' ' << *value_;
1138 out << ';';
1139 }
1140
1141 void Try::Output(CYOutput &out, CYFlags flags) const {
1142 out << "try" << ' ';
1143 out << '{' << '\n';
1144 ++out.indent_;
1145 out << code_;
1146 --out.indent_;
1147 out << '\t' << '}';
1148 out << catch_ << finally_;
1149 }
1150
1151 } }
1152
1153 void CYTypeCharacter::Output(CYOutput &out) const {
1154 switch (signing_) {
1155 case CYTypeNeutral: break;
1156 case CYTypeSigned: out << "signed" << ' '; break;
1157 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1158 }
1159
1160 out << "char";
1161 }
1162
1163 void CYTypeEnum::Output(CYOutput &out) const {
1164 out << "enum" << ' ';
1165 if (name_ != NULL)
1166 out << *name_;
1167 else {
1168 if (specifier_ != NULL)
1169 out << ':' << ' ' << *specifier_ << ' ';
1170
1171 out << '{' << '\n';
1172 ++out.indent_;
1173 bool comma(false);
1174
1175 CYForEach (constant, constants_) {
1176 if (comma)
1177 out << ',' << '\n';
1178 else
1179 comma = true;
1180 out << '\t' << constant->name_;
1181 out << ' ' << '=' << ' ' << constant->value_;
1182 }
1183
1184 if (out.pretty_)
1185 out << ',';
1186 out << '\n';
1187 --out.indent_;
1188 out << '\t' << '}';
1189 }
1190 }
1191
1192 void CYTypeError::Output(CYOutput &out) const {
1193 out << "@error";
1194 }
1195
1196 void CYTypeFloating::Output(CYOutput &out) const {
1197 switch (length_) {
1198 case 0: out << "float"; break;
1199 case 1: out << "double"; break;
1200 case 2: out << "long" << ' ' << "double"; break;
1201 default: _assert(false);
1202 }
1203 }
1204
1205 void CYTypeInt128::Output(CYOutput &out) const {
1206 switch (signing_) {
1207 case CYTypeNeutral: break;
1208 case CYTypeSigned: out << "signed" << ' '; break;
1209 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1210 }
1211
1212 out << "__int128";
1213 }
1214
1215 void CYTypeIntegral::Output(CYOutput &out) const {
1216 if (signing_ == CYTypeUnsigned)
1217 out << "unsigned" << ' ';
1218 switch (length_) {
1219 case 0: out << "short"; break;
1220 case 1: out << "int"; break;
1221 case 2: out << "long"; break;
1222 case 3: out << "long" << ' ' << "long"; break;
1223 default: _assert(false);
1224 }
1225 }
1226
1227 void CYTypeStruct::Output(CYOutput &out) const {
1228 out << "struct";
1229 if (name_ != NULL)
1230 out << ' ' << *name_;
1231 else
1232 out << *tail_;
1233 }
1234
1235 void CYTypeReference::Output(CYOutput &out) const {
1236 switch (kind_) {
1237 case CYTypeReferenceStruct: out << "struct"; break;
1238 case CYTypeReferenceEnum: out << "enum"; break;
1239 default: _assert(false);
1240 }
1241
1242 out << ' ' << *name_;
1243 }
1244
1245 void CYTypeVariable::Output(CYOutput &out) const {
1246 out << *name_;
1247 }
1248
1249 void CYTypeVoid::Output(CYOutput &out) const {
1250 out << "void";
1251 }
1252
1253 void CYVar::Output(CYOutput &out, CYFlags flags) const {
1254 out << "var" << ' ';
1255 bindings_->Output(out, flags); // XXX: flags
1256 out << ';';
1257 }
1258
1259 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
1260 out << *name_;
1261 }
1262
1263 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
1264 out << "while" << ' ' << '(' << *test_ << ')';
1265 code_->Single(out, CYRight(flags), CYCompactShort);
1266 }
1267
1268 void CYWith::Output(CYOutput &out, CYFlags flags) const {
1269 out << "with" << ' ' << '(' << *scope_ << ')';
1270 code_->Single(out, CYRight(flags), CYCompactShort);
1271 }
1272
1273 void CYWord::Output(CYOutput &out) const {
1274 out << Word();
1275 if (out.options_.verbose_) {
1276 out('@');
1277 char number[32];
1278 sprintf(number, "%p", this);
1279 out(number);
1280 }
1281 }
1282
1283 void CYWord::PropertyName(CYOutput &out) const {
1284 Output(out);
1285 }
1286
1287 const char *CYWord::Word() const {
1288 return word_;
1289 }