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