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