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