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