]> git.saurik.com Git - cycript.git/blame - Output.cpp
Allow users to tab complete struct and enum names.
[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 {
53cb77ff 461 out << "extern" << ' ' << abi_ << ' ' << typed_;
ffc2d225 462 out.Terminate();
c5587ed7
JF
463}
464
436a877b
JF
465void CYExternalExpression::Output(CYOutput &out, CYFlags flags) const {
466 out << '(' << "extern" << ' ' << abi_ << ' ' << typed_ << ')';
467}
468
a0be43fc 469void CYFatArrow::Output(CYOutput &out, CYFlags flags) const {
b0385401 470 out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << '{' << code_ << '}';
a0be43fc
JF
471}
472
b10bd496 473void CYFinally::Output(CYOutput &out) const {
b0385401
JF
474 out << ' ' << "finally" << ' ';
475 out << '{' << '\n';
476 ++out.indent_;
477 out << code_;
478 --out.indent_;
479 out << '\t' << '}';
b10bd496
JF
480}
481
fb98ac0c 482void CYFor::Output(CYOutput &out, CYFlags flags) const {
96a7e5c2 483 out << "for" << ' ' << '(';
09fc3efb
JF
484 if (initializer_ != NULL)
485 initializer_->Output(out, CYNoIn);
1fdca2fa 486 out.Terminate();
e661185c
JF
487 if (test_ != NULL)
488 out << ' ';
96a7e5c2 489 out << test_;
1fdca2fa 490 out.Terminate();
e661185c
JF
491 if (increment_ != NULL)
492 out << ' ';
96a7e5c2 493 out << increment_;
5999c315 494 out << ')';
efd689d8 495 code_->Single(out, CYRight(flags), CYCompactShort);
5999c315 496}
75b0a457 497
7085e1ab
JF
498void CYForLexical::Output(CYOutput &out, CYFlags flags) const {
499 out << (constant_ ? "const" : "let") << ' ';
09fc3efb 500 binding_->Output(out, CYRight(flags));
75b0a457
JF
501}
502
fb98ac0c 503void CYForIn::Output(CYOutput &out, CYFlags flags) const {
96a7e5c2 504 out << "for" << ' ' << '(';
09fc3efb
JF
505 initializer_->Output(out, CYNoIn | CYNoRightHand);
506 out << ' ' << "in" << ' ' << *iterable_ << ')';
efd689d8 507 code_->Single(out, CYRight(flags), CYCompactShort);
5999c315
JF
508}
509
23111dca
JF
510void CYForInitialized::Output(CYOutput &out, CYFlags flags) const {
511 out << "for" << ' ' << '(' << "var" << ' ';
09fc3efb
JF
512 binding_->Output(out, CYNoIn | CYNoRightHand);
513 out << ' ' << "in" << ' ' << *iterable_ << ')';
23111dca
JF
514 code_->Single(out, CYRight(flags), CYCompactShort);
515}
516
4644480a 517void CYForInComprehension::Output(CYOutput &out) const {
4e3c9056 518 out << "for" << ' ' << '(';
09fc3efb
JF
519 binding_->Output(out, CYNoIn | CYNoRightHand);
520 out << ' ' << "in" << ' ' << *iterable_ << ')';
75b0a457
JF
521}
522
7085e1ab
JF
523void CYForOf::Output(CYOutput &out, CYFlags flags) const {
524 out << "for" << ' ' << '(';
09fc3efb
JF
525 initializer_->Output(out, CYNoRightHand);
526 out << ' ' << "of" << ' ' << *iterable_ << ')';
7085e1ab
JF
527 code_->Single(out, CYRight(flags), CYCompactShort);
528}
529
530void CYForOfComprehension::Output(CYOutput &out) const {
531 out << "for" << ' ' << '(';
09fc3efb
JF
532 binding_->Output(out, CYNoRightHand);
533 out << ' ' << "of" << ' ' << *iterable_ << ')' << next_;
7085e1ab
JF
534}
535
536void CYForVariable::Output(CYOutput &out, CYFlags flags) const {
537 out << "var" << ' ';
09fc3efb 538 binding_->Output(out, CYRight(flags));
7085e1ab
JF
539}
540
c5b15840 541void CYFunction::Output(CYOutput &out) const {
b0385401
JF
542 out << '(' << parameters_ << ')' << ' ';
543 out << '{' << '\n';
544 ++out.indent_;
545 out << code_;
546 --out.indent_;
547 out << '\t' << '}';
fb98ac0c
JF
548}
549
550void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
c5b15840
JF
551 // XXX: one could imagine using + here to save a byte
552 bool protect((flags & CYNoFunction) != 0);
553 if (protect)
554 out << '(';
555 out << "function";
556 if (name_ != NULL)
557 out << ' ' << *name_;
558 CYFunction::Output(out);
559 if (protect)
560 out << ')';
fb98ac0c
JF
561}
562
563void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
c5b15840
JF
564 out << "function" << ' ' << *name_;
565 CYFunction::Output(out);
b09da87b
JF
566}
567
652ec1ba 568void CYFunctionParameter::Output(CYOutput &out) const {
09fc3efb 569 binding_->Output(out, CYNoFlags);
96a7e5c2
JF
570 if (next_ != NULL)
571 out << ',' << ' ' << *next_;
5999c315
JF
572}
573
029bc65b 574const char *CYIdentifier::Word() const {
7085e1ab 575 return next_ == NULL || next_ == this ? CYWord::Word() : next_->Word();
029bc65b
JF
576}
577
fb98ac0c
JF
578void CYIf::Output(CYOutput &out, CYFlags flags) const {
579 bool protect(false);
580 if (false_ == NULL && (flags & CYNoDangle) != 0) {
581 protect = true;
582 out << '{';
96a7e5c2 583 }
1fdca2fa
JF
584
585 out << "if" << ' ' << '(' << *test_ << ')';
586
fb98ac0c 587 CYFlags right(protect ? CYNoFlags : CYRight(flags));
d29365ce 588
fb98ac0c 589 CYFlags jacks(CYNoDangle);
96a7e5c2
JF
590 if (false_ == NULL)
591 jacks |= right;
d29365ce
JF
592 else
593 jacks |= protect ? CYNoFlags : CYCenter(flags);
1fdca2fa 594
efd689d8
JF
595 unsigned line(out.position_.line);
596 unsigned indent(out.indent_);
597 true_->Single(out, jacks, CYCompactShort);
1fdca2fa 598
5999c315 599 if (false_ != NULL) {
efd689d8
JF
600 if (out.position_.line != line && out.recent_ == indent)
601 out << ' ';
602 else
603 out << '\n' << '\t';
604
605 out << "else";
606 false_->Single(out, right, CYCompactLong);
5999c315 607 }
1fdca2fa 608
fb98ac0c
JF
609 if (protect)
610 out << '}';
5999c315
JF
611}
612
4644480a
JF
613void CYIfComprehension::Output(CYOutput &out) const {
614 out << "if" << ' ' << '(' << *test_ << ')' << next_;
75b0a457
JF
615}
616
7b750785
JF
617void CYImport::Output(CYOutput &out, CYFlags flags) const {
618 out << "@import";
619}
620
90dd6ff1
JF
621void CYImportDeclaration::Output(CYOutput &out, CYFlags flags) const {
622 _assert(false);
623}
624
7085e1ab
JF
625void CYIndirect::Output(CYOutput &out, CYFlags flags) const {
626 out << "*";
627 rhs_->Output(out, Precedence(), CYRight(flags));
628}
629
652ec1ba 630void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
9b5527f0 631 object_->Output(out, Precedence(), CYLeft(flags));
9b5527f0 632 if (const char *word = property_->Word())
3b52fd1a 633 out << "->" << word;
96a7e5c2 634 else
3b52fd1a 635 out << "->" << '[' << *property_ << ']';
5999c315
JF
636}
637
652ec1ba 638void CYInfix::Output(CYOutput &out, CYFlags flags) const {
b09da87b 639 const char *name(Operator());
d09e527c 640 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
b09da87b
JF
641 if (protect)
642 out << '(';
b09da87b 643 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
b09da87b 644 lhs_->Output(out, Precedence(), left);
96a7e5c2 645 out << ' ' << name << ' ';
b09da87b 646 CYFlags right(protect ? CYNoFlags : CYRight(flags));
b09da87b
JF
647 rhs_->Output(out, Precedence() - 1, right);
648 if (protect)
649 out << ')';
5999c315
JF
650}
651
3b52fd1a 652void CYLabel::Output(CYOutput &out, CYFlags flags) const {
efd689d8
JF
653 out << *name_ << ':';
654 statement_->Single(out, CYRight(flags), CYCompactShort);
3b52fd1a
JF
655}
656
b0385401
JF
657void CYParenthetical::Output(CYOutput &out, CYFlags flags) const {
658 out << '(';
659 expression_->Output(out, CYCompound::Precedence_, CYNoFlags);
660 out << ')';
661}
662
663void CYStatement::Output(CYOutput &out) const {
664 Multiple(out);
665}
666
b900e1a4
JF
667void CYTemplate::Output(CYOutput &out, CYFlags flags) const {
668 _assert(false);
669}
670
9a39f705 671void CYTypeArrayOf::Output(CYOutput &out, CYIdentifier *identifier) const {
53cb77ff 672 next_->Output(out, Precedence(), identifier, false);
9a39f705
JF
673 out << '[';
674 out << size_;
675 out << ']';
676}
677
3fe16be7
JF
678void CYTypeBlockWith::Output(CYOutput &out, CYIdentifier *identifier) const {
679 out << '(' << '^';
53cb77ff 680 next_->Output(out, Precedence(), identifier, false);
3fe16be7
JF
681 out << ')' << '(' << parameters_ << ')';
682}
683
9a39f705 684void CYTypeConstant::Output(CYOutput &out, CYIdentifier *identifier) const {
53cb77ff
JF
685 out << "const";
686 next_->Output(out, Precedence(), identifier, false);
9a39f705
JF
687}
688
689void CYTypeFunctionWith::Output(CYOutput &out, CYIdentifier *identifier) const {
53cb77ff 690 next_->Output(out, Precedence(), identifier, false);
574d4720
JF
691 out << '(' << parameters_;
692 if (variadic_) {
693 if (parameters_ != NULL)
694 out << ',' << ' ';
695 out << "...";
696 }
697 out << ')';
9a39f705
JF
698}
699
700void CYTypePointerTo::Output(CYOutput &out, CYIdentifier *identifier) const {
701 out << '*';
53cb77ff 702 next_->Output(out, Precedence(), identifier, false);
9a39f705
JF
703}
704
705void CYTypeVolatile::Output(CYOutput &out, CYIdentifier *identifier) const {
706 out << "volatile";
53cb77ff 707 next_->Output(out, Precedence(), identifier, true);
9a39f705
JF
708}
709
53cb77ff
JF
710void CYTypeModifier::Output(CYOutput &out, int precedence, CYIdentifier *identifier, bool space) const {
711 if (this == NULL && identifier == NULL)
712 return;
713 else if (space)
714 out << ' ';
715
9a39f705
JF
716 if (this == NULL) {
717 out << identifier;
718 return;
719 }
720
721 bool protect(precedence > Precedence());
722
723 if (protect)
724 out << '(';
725 Output(out, identifier);
726 if (protect)
727 out << ')';
728}
729
60097023 730void CYTypedIdentifier::Output(CYOutput &out) const {
aaa29c28 731 out << *specifier_;
53cb77ff 732 modifier_->Output(out, 0, identifier_, true);
9a39f705
JF
733}
734
735void CYEncodedType::Output(CYOutput &out, CYFlags flags) const {
736 out << "@encode(" << typed_ << ")";
737}
738
739void CYTypedParameter::Output(CYOutput &out) const {
740 out << typed_;
741 if (next_ != NULL)
742 out << ',' << ' ' << next_;
60097023
JF
743}
744
690cf1a8
JF
745void CYLambda::Output(CYOutput &out, CYFlags flags) const {
746 // XXX: this is seriously wrong
747 out << "[](";
748 out << ")->";
749 out << "{";
750 out << "}";
751}
752
60097023 753void CYTypeDefinition::Output(CYOutput &out, CYFlags flags) const {
efd689d8 754 out << "typedef" << ' ' << *typed_;
ffc2d225 755 out.Terminate();
60097023
JF
756}
757
64a505ff
JF
758void CYTypeExpression::Output(CYOutput &out, CYFlags flags) const {
759 out << '(' << "typedef" << ' ' << *typed_ << ')';
760}
761
09fc3efb 762void CYLexical::Output(CYOutput &out, CYFlags flags) const {
ca6a1b2b 763 out << "let" << ' ';
09fc3efb 764 bindings_->Output(out, flags); // XXX: flags
ca6a1b2b 765 out << ';';
cac61857
JF
766}
767
7b750785
JF
768void CYModule::Output(CYOutput &out) const {
769 out << part_;
770 if (next_ != NULL)
771 out << '.' << next_;
772}
773
2eb8215d
JF
774namespace cy {
775namespace Syntax {
776
777void New::Output(CYOutput &out, CYFlags flags) const {
96a7e5c2 778 out << "new" << ' ';
11c1cc16 779 CYFlags jacks(CYNoCall | CYCenter(flags));
11c1cc16 780 constructor_->Output(out, Precedence(), jacks);
96a7e5c2
JF
781 if (arguments_ != NULL)
782 out << '(' << *arguments_ << ')';
5999c315
JF
783}
784
2eb8215d
JF
785} }
786
652ec1ba 787void CYNull::Output(CYOutput &out, CYFlags flags) const {
8f56307d 788 out << "null";
5999c315
JF
789}
790
652ec1ba 791void CYNumber::Output(CYOutput &out, CYFlags flags) const {
856b8cd0
JF
792 std::ostringstream str;
793 CYNumerify(str, Value());
9561f209
JF
794 std::string value(str.str());
795 out << value.c_str();
796 // XXX: this should probably also handle hex conversions and exponents
797 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
798 out << '.';
5999c315
JF
799}
800
652ec1ba 801void CYNumber::PropertyName(CYOutput &out) const {
fb98ac0c 802 Output(out, CYNoFlags);
e5bc40db
JF
803}
804
652ec1ba 805void CYObject::Output(CYOutput &out, CYFlags flags) const {
b09da87b
JF
806 bool protect((flags & CYNoBrace) != 0);
807 if (protect)
808 out << '(';
c0bc320e
JF
809 out << '{' << '\n';
810 ++out.indent_;
3b52fd1a 811 out << properties_;
c0bc320e
JF
812 --out.indent_;
813 out << '\t' << '}';
b09da87b
JF
814 if (protect)
815 out << ')';
693d501b
JF
816}
817
652ec1ba 818void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
b09da87b 819 lhs_->Output(out, Precedence(), CYLeft(flags));
d35a3b07 820 out << Operator();
5999c315
JF
821}
822
652ec1ba 823void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
1ef7d061 824 const char *name(Operator());
1ef7d061 825 out << name;
96a7e5c2 826 if (Alphabetic())
11c1cc16 827 out << ' ';
96a7e5c2 828 rhs_->Output(out, Precedence(), CYRight(flags));
5999c315
JF
829}
830
a7d8b413 831void CYScript::Output(CYOutput &out) const {
b0385401 832 out << code_;
3b52fd1a
JF
833}
834
652ec1ba 835void CYProperty::Output(CYOutput &out) const {
c5b15840
JF
836 if (next_ != NULL || out.pretty_)
837 out << ',';
838 out << '\n' << next_;
839}
840
841void CYPropertyGetter::Output(CYOutput &out) const {
842 out << "get" << ' ';
843 name_->PropertyName(out);
844 CYFunction::Output(out);
845 CYProperty::Output(out);
846}
847
848void CYPropertyMethod::Output(CYOutput &out) const {
849 name_->PropertyName(out);
850 CYFunction::Output(out);
851 CYProperty::Output(out);
852}
853
854void CYPropertySetter::Output(CYOutput &out) const {
855 out << "set" << ' ';
856 name_->PropertyName(out);
857 CYFunction::Output(out);
858 CYProperty::Output(out);
859}
860
861void CYPropertyValue::Output(CYOutput &out) const {
c0bc320e 862 out << '\t';
e5bc40db 863 name_->PropertyName(out);
96a7e5c2 864 out << ':' << ' ';
8351aa30 865 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
c5b15840 866 CYProperty::Output(out);
5999c315
JF
867}
868
63cd45c9
JF
869void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
870 out << Value();
63cd45c9
JF
871}
872
2fad14e5
JF
873void CYResolveMember::Output(CYOutput &out, CYFlags flags) const {
874 object_->Output(out, Precedence(), CYLeft(flags));
875 if (const char *word = property_->Word())
876 out << "::" << word;
877 else
878 out << "::" << '[' << *property_ << ']';
879}
880
fb98ac0c 881void CYReturn::Output(CYOutput &out, CYFlags flags) const {
c0bc320e
JF
882 out << "return";
883 if (value_ != NULL)
884 out << ' ' << *value_;
885 out << ';';
5999c315
JF
886}
887
6c093cce 888void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
4f3e597c 889 lhs_->Output(out, CYLeft(flags));
6c093cce
JF
890 out << ' ';
891 proc_->Output(out, CYRight(flags));
892}
893
894void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
0da459fc 895 out << '{' << ' ' << '|' << parameters_ << '|' << '\n';
b0385401 896 ++out.indent_;
6c093cce 897 out << code_;
b0385401
JF
898 --out.indent_;
899 out << '\t' << '}';
6c093cce
JF
900}
901
e56c2499
JF
902void CYSubscriptMember::Output(CYOutput &out, CYFlags flags) const {
903 object_->Output(out, Precedence(), CYLeft(flags));
904 out << "." << '[' << *property_ << ']';
905}
906
fb98ac0c
JF
907void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
908 bool first(true);
c2c9f509 909 CYForEach (next, this) {
fb98ac0c 910 bool last(next->next_ == NULL);
7bf4a0cd 911 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
fb98ac0c 912 first = false;
1fdca2fa 913 out << '\t';
fb98ac0c 914 next->Output(out, jacks);
1fdca2fa 915 out << '\n';
fb98ac0c 916 }
5999c315
JF
917}
918
efd689d8 919void CYStatement::Single(CYOutput &out, CYFlags flags, CYCompactType request) const {
0f37eca9
JF
920 if (this == NULL)
921 return out.Terminate();
922
3b52fd1a 923 _assert(next_ == NULL);
efd689d8
JF
924
925 CYCompactType compact(Compact());
926
927 if (compact >= request)
928 out << ' ';
929 else {
930 out << '\n';
931 ++out.indent_;
932 out << '\t';
933 }
934
3b52fd1a 935 Output(out, flags);
efd689d8
JF
936
937 if (compact < request)
938 --out.indent_;
5999c315
JF
939}
940
652ec1ba 941void CYString::Output(CYOutput &out, CYFlags flags) const {
96a7e5c2 942 std::ostringstream str;
520c130f 943 CYStringify(str, value_, size_);
96a7e5c2 944 out << str.str().c_str();
5999c315
JF
945}
946
652ec1ba 947void CYString::PropertyName(CYOutput &out) const {
e5bc40db
JF
948 if (const char *word = Word())
949 out << word;
950 else
96a7e5c2 951 out << *this;
e5bc40db
JF
952}
953
c0bc320e
JF
954static const char *Reserved_[] = {
955 "false", "null", "true",
956
957 "break", "case", "catch", "continue", "default",
958 "delete", "do", "else", "finally", "for", "function",
959 "if", "in", "instanceof", "new", "return", "switch",
960 "this", "throw", "try", "typeof", "var", "void",
961 "while", "with",
962
963 "debugger", "const",
964
965 "class", "enum", "export", "extends", "import", "super",
966
967 "abstract", "boolean", "byte", "char", "double", "final",
968 "float", "goto", "int", "long", "native", "short",
969 "synchronized", "throws", "transient", "volatile",
970
971 "let", "yield",
972
c0bc320e
JF
973 NULL
974};
975
11c1cc16
JF
976const char *CYString::Word() const {
977 if (size_ == 0 || !WordStartRange_[value_[0]])
978 return NULL;
979 for (size_t i(1); i != size_; ++i)
980 if (!WordEndRange_[value_[i]])
981 return NULL;
982 const char *value(Value());
c0bc320e 983 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
11c1cc16
JF
984 if (strcmp(*reserved, value) == 0)
985 return NULL;
986 return value;
987}
988
d8380373
JF
989void CYStructDefinition::Output(CYOutput &out, CYFlags flags) const {
990 out << "struct" << ' ' << *name_ << *tail_;
991}
992
993void CYStructTail::Output(CYOutput &out) const {
994 out << ' ' << '{' << '\n';
995 ++out.indent_;
996 CYForEach (field, fields_) {
997 out << '\t' << *field->typed_;
998 out.Terminate();
999 out << '\n';
1000 }
1001 --out.indent_;
53cb77ff 1002 out << '\t' << '}';
d8380373
JF
1003}
1004
c5b15840
JF
1005void CYSuperAccess::Output(CYOutput &out, CYFlags flags) const {
1006 out << "super";
1007 if (const char *word = property_->Word())
1008 out << '.' << word;
1009 else
1010 out << '[' << *property_ << ']';
1011}
1012
1013void CYSuperCall::Output(CYOutput &out, CYFlags flags) const {
1014 out << "super" << '(' << arguments_ << ')';
1015}
1016
fb98ac0c 1017void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
efd689d8
JF
1018 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{' << '\n';
1019 ++out.indent_;
96a7e5c2 1020 out << clauses_;
efd689d8
JF
1021 --out.indent_;
1022 out << '\t' << '}';
5999c315
JF
1023}
1024
2fad14e5
JF
1025void CYSymbol::Output(CYOutput &out, CYFlags flags) const {
1026 bool protect((flags & CYNoColon) != 0);
1027 if (protect)
1028 out << '(';
1029 out << ':' << name_;
1030 if (protect)
1031 out << ')';
1032}
1033
652ec1ba 1034void CYThis::Output(CYOutput &out, CYFlags flags) const {
8f56307d 1035 out << "this";
5999c315
JF
1036}
1037
37954781
JF
1038namespace cy {
1039namespace Syntax {
1040
1041void Throw::Output(CYOutput &out, CYFlags flags) const {
c0bc320e
JF
1042 out << "throw";
1043 if (value_ != NULL)
1044 out << ' ' << *value_;
1045 out << ';';
5999c315
JF
1046}
1047
37954781 1048void Try::Output(CYOutput &out, CYFlags flags) const {
b0385401
JF
1049 out << "try" << ' ';
1050 out << '{' << '\n';
1051 ++out.indent_;
1052 out << code_;
1053 --out.indent_;
1054 out << '\t' << '}';
1055 out << catch_ << finally_;
5999c315
JF
1056}
1057
37954781
JF
1058} }
1059
0559abf8
JF
1060void CYTypeCharacter::Output(CYOutput &out) const {
1061 switch (signing_) {
1062 case CYTypeNeutral: break;
1063 case CYTypeSigned: out << "signed" << ' '; break;
1064 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1065 }
03db6a67 1066
0559abf8 1067 out << "char";
3fe283c5
JF
1068}
1069
aaa29c28
JF
1070void CYTypeEnum::Output(CYOutput &out) const {
1071 out << "enum" << ' ';
1072 if (name_ != NULL)
1073 out << *name_;
1074 else {
1075 if (specifier_ != NULL)
1076 out << ':' << ' ' << *specifier_ << ' ';
1077
1078 out << '{' << '\n';
1079 ++out.indent_;
1080 bool comma(false);
1081
1082 CYForEach (constant, constants_) {
1083 if (comma)
1084 out << ',' << '\n';
1085 else
1086 comma = true;
1087 out << '\t' << constant->name_;
1088 out << ' ' << '=' << ' ' << constant->value_;
1089 }
1090
1091 if (out.pretty_)
1092 out << ',';
1093 out << '\n';
1094 --out.indent_;
1095 out << '\t' << '}';
1096 }
1097}
1098
0559abf8
JF
1099void CYTypeError::Output(CYOutput &out) const {
1100 out << "@error";
3fe283c5
JF
1101}
1102
24ffc58c
JF
1103void CYTypeInt128::Output(CYOutput &out) const {
1104 switch (signing_) {
1105 case CYTypeNeutral: break;
1106 case CYTypeSigned: out << "signed" << ' '; break;
1107 case CYTypeUnsigned: out << "unsigned" << ' '; break;
1108 }
1109
1110 out << "__int128";
1111}
1112
0559abf8
JF
1113void CYTypeIntegral::Output(CYOutput &out) const {
1114 if (signing_ == CYTypeUnsigned)
1115 out << "unsigned" << ' ';
1116 switch (length_) {
1117 case 0: out << "short"; break;
1118 case 1: out << "int"; break;
1119 case 2: out << "long"; break;
1120 case 3: out << "long" << ' ' << "long"; break;
1121 default: _assert(false);
1122 }
3fe283c5
JF
1123}
1124
b3c38c5f 1125void CYTypeStruct::Output(CYOutput &out) const {
d8380373 1126 out << "struct";
b3c38c5f 1127 if (name_ != NULL)
d8380373
JF
1128 out << ' ' << *name_;
1129 else
1130 out << *tail_;
b3c38c5f
JF
1131}
1132
d8380373 1133void CYTypeReference::Output(CYOutput &out) const {
aaa29c28
JF
1134 switch (kind_) {
1135 case CYTypeReferenceStruct: out << "struct"; break;
1136 case CYTypeReferenceEnum: out << "enum"; break;
1137 default: _assert(false);
1138 }
1139
1140 out << ' ' << *name_;
d8380373
JF
1141}
1142
3fe283c5
JF
1143void CYTypeVariable::Output(CYOutput &out) const {
1144 out << *name_;
1145}
1146
1147void CYTypeVoid::Output(CYOutput &out) const {
1148 out << "void";
1149}
1150
fb98ac0c 1151void CYVar::Output(CYOutput &out, CYFlags flags) const {
efd689d8 1152 out << "var" << ' ';
09fc3efb 1153 bindings_->Output(out, flags); // XXX: flags
96a7e5c2 1154 out << ';';
cac61857
JF
1155}
1156
652ec1ba 1157void CYVariable::Output(CYOutput &out, CYFlags flags) const {
5999c315
JF
1158 out << *name_;
1159}
1160
fb98ac0c 1161void CYWhile::Output(CYOutput &out, CYFlags flags) const {
efd689d8
JF
1162 out << "while" << ' ' << '(' << *test_ << ')';
1163 code_->Single(out, CYRight(flags), CYCompactShort);
5999c315
JF
1164}
1165
fb98ac0c 1166void CYWith::Output(CYOutput &out, CYFlags flags) const {
efd689d8
JF
1167 out << "with" << ' ' << '(' << *scope_ << ')';
1168 code_->Single(out, CYRight(flags), CYCompactShort);
5999c315
JF
1169}
1170
652ec1ba 1171void CYWord::Output(CYOutput &out) const {
029bc65b 1172 out << Word();
efd689d8
JF
1173 if (out.options_.verbose_) {
1174 out('@');
1175 char number[32];
1176 sprintf(number, "%p", this);
1177 out(number);
1178 }
5999c315 1179}
e5bc40db 1180
652ec1ba 1181void CYWord::PropertyName(CYOutput &out) const {
e5bc40db
JF
1182 Output(out);
1183}
029bc65b
JF
1184
1185const char *CYWord::Word() const {
1186 return word_;
1187}