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