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