]> git.saurik.com Git - cycript.git/blob - Output.cpp
f8885247ca89d867ef62e9bfb5e6ee81ba87add3
[cycript.git] / Output.cpp
1 #include "Parser.hpp"
2
3 #include <iostream>
4 #include <iomanip>
5
6 #include <objc/runtime.h>
7 #include <sstream>
8
9 _finline CYFlags operator ~(CYFlags rhs) {
10 return static_cast<CYFlags>(~static_cast<unsigned>(rhs));
11 }
12
13 _finline CYFlags operator &(CYFlags lhs, CYFlags rhs) {
14 return static_cast<CYFlags>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs));
15 }
16
17 _finline CYFlags operator |(CYFlags lhs, CYFlags rhs) {
18 return static_cast<CYFlags>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs));
19 }
20
21 _finline CYFlags &operator |=(CYFlags &lhs, CYFlags rhs) {
22 return lhs = lhs | rhs;
23 }
24
25 _finline CYFlags CYLeft(CYFlags flags) {
26 return flags & ~CYNoDangle;
27 }
28
29 _finline CYFlags CYRight(CYFlags flags) {
30 return flags & ~CYNoBF;
31 }
32
33 _finline CYFlags CYCenter(CYFlags flags) {
34 return CYLeft(CYRight(flags));
35 }
36
37 #define CYPA 16
38
39 void CYOutput::Terminate() {
40 out_ << ';';
41 mode_ = NoMode;
42 }
43
44 CYOutput &CYOutput::operator <<(char rhs) {
45 if (rhs == ' ' || rhs == '\n')
46 if (pretty_)
47 out_ << rhs;
48 else goto done;
49 else if (rhs == '\t')
50 if (pretty_)
51 for (unsigned i(0); i != indent_; ++i)
52 out_ << " ";
53 else goto done;
54 else goto work;
55
56 mode_ = NoMode;
57 goto done;
58
59 work:
60 if (mode_ == Terminated && rhs != '}')
61 out_ << ';';
62
63 if (rhs == ';') {
64 if (pretty_)
65 goto none;
66 else {
67 mode_ = Terminated;
68 goto done;
69 }
70 } else if (rhs == '-') {
71 if (mode_ == NoHyphen)
72 out_ << ' ';
73 mode_ = NoHyphen;
74 } else if (WordEndRange_[rhs]) {
75 if (mode_ == NoLetter)
76 out_ << ' ';
77 mode_ = NoLetter;
78 } else none:
79 mode_ = NoMode;
80
81 out_ << rhs;
82 done:
83 return *this;
84 }
85
86 CYOutput &CYOutput::operator <<(const char *rhs) {
87 size_t size(strlen(rhs));
88
89 if (size == 1)
90 return *this << *rhs;
91
92 if (mode_ == Terminated)
93 out_ << ';';
94 else if (
95 mode_ == NoHyphen && *rhs == '-' ||
96 mode_ == NoLetter && WordEndRange_[*rhs]
97 )
98 out_ << ' ';
99
100 if (WordEndRange_[rhs[size - 1]])
101 mode_ = NoLetter;
102 else
103 mode_ = NoMode;
104
105 out_ << rhs;
106 return *this;
107 }
108
109 void OutputBody(CYOutput &out, CYStatement *body) {
110 out << ' ' << '{' << '\n';
111 ++out.indent_;
112 if (body != NULL)
113 body->Multiple(out);
114 --out.indent_;
115 out << '\t' << '}';
116 }
117
118 void CYAddressOf::Output(CYOutput &out, CYFlags flags) const {
119 rhs_->Output(out, 1, CYLeft(flags));
120 out << ".$cya()";
121 }
122
123 void CYArgument::Output(CYOutput &out) const {
124 if (name_ != NULL) {
125 out << *name_;
126 if (value_ != NULL)
127 out << ':' << ' ';
128 }
129 if (value_ != NULL)
130 value_->Output(out, CYPA, CYNoFlags);
131 if (next_ != NULL) {
132 if (next_->name_ == NULL)
133 out << ',';
134 out << ' ' << *next_;
135 }
136 }
137
138 void CYArray::Output(CYOutput &out, CYFlags flags) const {
139 out << '[' << elements_ << ']';
140 }
141
142 void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
143 // XXX: I don't necc. need the ()s
144 out << "(function($cyv";
145 for (CYComprehension *comprehension(comprehensions_); comprehension != NULL; comprehension = comprehension->next_)
146 if (const char *name = comprehension->Name())
147 out << ',' << name;
148 out << "){";
149 out << "$cyv=[];";
150 comprehensions_->Output(out);
151 out << "$cyv.push(";
152 expression_->Output(out, CYPA, CYNoFlags);
153 out << ");";
154 for (CYComprehension *comprehension(comprehensions_); comprehension != NULL; comprehension = comprehension->next_)
155 comprehension->End_(out);
156 out << "return $cyv;";
157 out << "}())";
158 }
159
160 void CYAssignment::Output(CYOutput &out, CYFlags flags) const {
161 lhs_->Output(out, Precedence() - 1, CYLeft(flags) | CYNoRightHand);
162 out << ' ' << Operator() << ' ';
163 rhs_->Output(out, Precedence(), CYRight(flags));
164 }
165
166 void CYBlock::Output(CYOutput &out, CYFlags flags) const {
167 statements_->Single(out, flags);
168 }
169
170 void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
171 out << (Value() ? "true" : "false");
172 }
173
174 void CYBreak::Output(CYOutput &out, CYFlags flags) const {
175 out << "break";
176 if (label_ != NULL)
177 out << ' ' << *label_;
178 out << ';';
179 }
180
181 void CYCall::Output(CYOutput &out, CYFlags flags) const {
182 bool protect((flags & CYNoCall) != 0);
183 if (protect)
184 out << '(';
185 function_->Output(out, Precedence(), protect ? CYNoFlags : flags);
186 out << '(' << arguments_ << ')';
187 if (protect)
188 out << ')';
189 }
190
191 void CYCatch::Output(CYOutput &out) const {
192 out << "catch" << ' ' << '(' << *name_ << ')' << ' ' << '{';
193 if (code_ != NULL)
194 code_->Multiple(out);
195 out << '}';
196 }
197
198 void CYCategory::Output(CYOutput &out, CYFlags flags) const {
199 out << "(function($cys,$cyp,$cyc,$cyn,$cyt){";
200 out << "$cyp=object_getClass($cys);";
201 out << "$cyc=$cys;";
202 if (messages_ != NULL)
203 messages_->Output(out, true);
204 out << "})(";
205 name_->ClassName(out, true);
206 out << ')';
207 out << ';';
208 }
209
210 void CYClass::Output(CYOutput &out, CYFlags flags) const {
211 // XXX: I don't necc. need the ()s
212 out << "(function($cys,$cyp,$cyc,$cyn,$cyt,$cym){";
213 out << "$cyp=object_getClass($cys);";
214 out << "$cyc=objc_allocateClassPair($cys,";
215 if (name_ != NULL)
216 name_->ClassName(out, false);
217 else
218 out << "$cyq(\"CY$\")";
219 out << ",0);";
220 out << "$cym=object_getClass($cyc);";
221 if (fields_ != NULL)
222 fields_->Output(out);
223 if (messages_ != NULL)
224 messages_->Output(out, false);
225 out << "objc_registerClassPair($cyc);";
226 out << "return $cyc;";
227 out << "}(";
228 if (super_ != NULL)
229 super_->Output(out, CYPA, CYNoFlags);
230 else
231 out << "null";
232 out << "))";
233 }
234
235 void CYClassExpression::Output(CYOutput &out, CYFlags flags) const {
236 CYClass::Output(out, flags);
237 }
238
239 void CYClassStatement::Output(CYOutput &out, CYFlags flags) const {
240 CYClass::Output(out, flags);
241 }
242
243 void CYCompound::Output(CYOutput &out, CYFlags flags) const {
244 if (CYExpression *expression = expressions_)
245 if (CYExpression *next = expression->next_) {
246 expression->Output(out, CYLeft(flags));
247 CYFlags center(CYCenter(flags));
248 while (next != NULL) {
249 expression = next;
250 out << ',' << ' ';
251 next = expression->next_;
252 CYFlags right(next != NULL ? center : CYRight(flags));
253 expression->Output(out, right);
254 }
255 } else
256 expression->Output(out, flags);
257 }
258
259 void CYComprehension::Output(CYOutput &out) const {
260 Begin_(out);
261 out << next_;
262 }
263
264 void CYCondition::Output(CYOutput &out, CYFlags flags) const {
265 test_->Output(out, Precedence() - 1, CYLeft(flags));
266 out << ' ' << '?' << ' ';
267 if (true_ != NULL)
268 true_->Output(out, CYPA, CYNoFlags);
269 out << ' ' << ':' << ' ';
270 false_->Output(out, CYPA, CYRight(flags));
271 }
272
273 void CYContinue::Output(CYOutput &out, CYFlags flags) const {
274 out << "continue";
275 if (label_ != NULL)
276 out << ' ' << *label_;
277 out << ';';
278 }
279
280 void CYClause::Output(CYOutput &out) const {
281 if (case_ != NULL)
282 out << "case" << ' ' << *case_;
283 else
284 out << "default";
285 out << ':' << '\n';
286 if (code_ != NULL)
287 code_->Multiple(out, CYNoFlags);
288 out << next_;
289 }
290
291 const char *CYDeclaration::ForEachIn() const {
292 return identifier_->Value();
293 }
294
295 void CYDeclaration::ForIn(CYOutput &out, CYFlags flags) const {
296 out << "var";
297 Output(out, CYRight(flags));
298 }
299
300 void CYDeclaration::ForEachIn(CYOutput &out) const {
301 out << *identifier_;
302 }
303
304 void CYDeclaration::Output(CYOutput &out, CYFlags flags) const {
305 out << *identifier_;
306 if (initialiser_ != NULL) {
307 out << ' ' << '=' << ' ';
308 initialiser_->Output(out, CYPA, CYRight(flags));
309 }
310 }
311
312 void CYDeclarations::For(CYOutput &out) const {
313 out << "var";
314 Output(out, CYNoIn);
315 }
316
317 void CYDeclarations::Output(CYOutput &out) const {
318 Output(out, CYNoFlags);
319 }
320
321 void CYDeclarations::Output(CYOutput &out, CYFlags flags) const {
322 const CYDeclarations *declaration(this);
323 bool first(true);
324 output:
325 CYDeclarations *next(declaration->next_);
326 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
327 first = false;
328 declaration->declaration_->Output(out, jacks);
329
330 if (next != NULL) {
331 out << ',' << ' ';
332 declaration = next;
333 goto output;
334 }
335 }
336
337 void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
338 object_->Output(out, Precedence(), CYLeft(flags));
339 if (const char *word = property_->Word())
340 out << '.' << word;
341 else
342 out << '[' << *property_ << ']';
343 }
344
345 void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
346 out << "do";
347 code_->Single(out, CYCenter(flags));
348 out << "while" << ' ' << '(' << *test_ << ')';
349 }
350
351 void CYElement::Output(CYOutput &out) const {
352 if (value_ != NULL)
353 value_->Output(out, CYPA, CYNoFlags);
354 if (next_ != NULL || value_ == NULL) {
355 out << ',';
356 if (next_ != NULL && next_->value_ != NULL)
357 out << ' ';
358 }
359 if (next_ != NULL)
360 next_->Output(out);
361 }
362
363 void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
364 out.Terminate();
365 }
366
367 void CYExpress::Output(CYOutput &out, CYFlags flags) const {
368 expression_->Output(out, flags | CYNoBF);
369 out << ';';
370 }
371
372 void CYExpression::ClassName(CYOutput &out, bool object) const {
373 Output(out, CYPA, CYNoFlags);
374 }
375
376 const char *CYExpression::ForEachIn() const {
377 return NULL;
378 }
379
380 void CYExpression::For(CYOutput &out) const {
381 Output(out, CYNoIn);
382 }
383
384 void CYExpression::ForEachIn(CYOutput &out) const {
385 Output(out, CYPA, CYNoRightHand);
386 }
387
388 void CYExpression::ForIn(CYOutput &out, CYFlags flags) const {
389 Output(out, flags | CYNoRightHand);
390 }
391
392 void CYExpression::Output(CYOutput &out) const {
393 Output(out, CYNoFlags);
394 }
395
396 void CYExpression::Output(CYOutput &out, unsigned precedence, CYFlags flags) const {
397 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
398 out << '(' << *this << ')';
399 else
400 Output(out, flags);
401 }
402
403 void CYField::Output(CYOutput &out) const {
404 // XXX: implement!
405 }
406
407 void CYFinally::Output(CYOutput &out) const {
408 out << "finally" << ' ' << '{';
409 if (code_ != NULL)
410 code_->Multiple(out);
411 out << '}';
412 }
413
414 void CYFor::Output(CYOutput &out, CYFlags flags) const {
415 out << "for" << ' ' << '(';
416 if (initialiser_ != NULL)
417 initialiser_->For(out);
418 out.Terminate();
419 out << test_;
420 out.Terminate();
421 out << increment_;
422 out << ')';
423 code_->Single(out, CYRight(flags));
424 }
425
426 void CYForEachIn::Output(CYOutput &out, CYFlags flags) const {
427 out << "with({$cys:0,$cyt:0}){";
428
429 out << "$cys=";
430 set_->Output(out, CYPA, CYNoFlags);
431 out << ';';
432
433 out << "for($cyt in $cys){";
434
435 initialiser_->ForEachIn(out);
436 out << "=$cys[$cyt];";
437
438 code_->Multiple(out);
439
440 out << '}';
441
442 out << '}';
443 }
444
445 void CYForEachInComprehension::Begin_(CYOutput &out) const {
446 out << "(function($cys){";
447 out << "$cys=";
448 set_->Output(out, CYPA, CYNoFlags);
449 out << ';';
450
451 out << "for(" << *name_ << " in $cys){";
452 out << *name_ << "=$cys[" << *name_ << "];";
453 }
454
455 void CYForEachInComprehension::End_(CYOutput &out) const {
456 out << "}}());";
457 }
458
459 void CYForIn::Output(CYOutput &out, CYFlags flags) const {
460 out << "for" << ' ' << '(';
461 initialiser_->ForIn(out, CYNoIn);
462 out << "in" << *set_ << ')';
463 code_->Single(out, CYRight(flags));
464 }
465
466 void CYForInComprehension::Begin_(CYOutput &out) const {
467 out << "for" << ' ' << '(' << *name_ << "in" << *set_ << ')';
468 }
469
470 void CYFunction::Output(CYOutput &out, CYFlags flags) const {
471 // XXX: one could imagine using + here to save a byte
472 bool protect((flags & CYNoFunction) != 0);
473 if (protect)
474 out << '(';
475 out << "function";
476 if (name_ != NULL)
477 out << ' ' << *name_;
478 out << '(' << parameters_ << ')';
479 OutputBody(out, body_);
480 if (protect)
481 out << ')';
482 }
483
484 void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
485 CYFunction::Output(out, flags);
486 }
487
488 void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
489 CYFunction::Output(out, flags);
490 }
491
492 void CYFunctionParameter::Output(CYOutput &out) const {
493 out << *name_;
494 if (next_ != NULL)
495 out << ',' << ' ' << *next_;
496 }
497
498 void CYIf::Output(CYOutput &out, CYFlags flags) const {
499 bool protect(false);
500 if (false_ == NULL && (flags & CYNoDangle) != 0) {
501 protect = true;
502 out << '{';
503 }
504
505 out << "if" << ' ' << '(' << *test_ << ')';
506
507 CYFlags right(protect ? CYNoFlags : CYRight(flags));
508
509 CYFlags jacks(CYNoDangle);
510 if (false_ == NULL)
511 jacks |= right;
512 else
513 jacks |= protect ? CYNoFlags : CYCenter(flags);
514
515 bool single(true_->Single(out, jacks));
516
517 if (false_ != NULL) {
518 out << (single ? '\t' : ' ');
519 out << "else";
520 false_->Single(out, right);
521 }
522
523 if (protect)
524 out << '}';
525 }
526
527 void CYIfComprehension::Begin_(CYOutput &out) const {
528 out << "if" << '(' << *test_ << ')';
529 }
530
531 void CYIndirect::Output(CYOutput &out, CYFlags flags) const {
532 rhs_->Output(out, 1, CYLeft(flags));
533 out << ".$cyi";
534 }
535
536 void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
537 object_->Output(out, Precedence(), CYLeft(flags));
538 out << ".$cyi";
539 if (const char *word = property_->Word())
540 out << '.' << word;
541 else
542 out << '[' << *property_ << ']';
543 }
544
545 void CYInfix::Output(CYOutput &out, CYFlags flags) const {
546 const char *name(Operator());
547 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in"));
548 if (protect)
549 out << '(';
550 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
551 lhs_->Output(out, Precedence(), left);
552 out << ' ' << name << ' ';
553 CYFlags right(protect ? CYNoFlags : CYRight(flags));
554 rhs_->Output(out, Precedence() - 1, right);
555 if (protect)
556 out << ')';
557 }
558
559 void CYLet::Output(CYOutput &out, CYFlags flags) const {
560 out << "let" << ' ' << '(' << *declarations_ << ')' << ' ' << '{';
561 if (statements_ != NULL)
562 statements_->Multiple(out);
563 out << '}';
564 }
565
566 void CYMessage::Output(CYOutput &out, bool replace) const {
567 if (next_ != NULL)
568 next_->Output(out, replace);
569 out << "$cyn=new Selector(\"";
570 for (CYMessageParameter *parameter(parameter_); parameter != NULL; parameter = parameter->next_)
571 if (parameter->tag_ != NULL) {
572 out << *parameter->tag_;
573 if (parameter->name_ != NULL)
574 out << ':';
575 }
576 out << "\");";
577 out << "$cyt=$cyn.type($cy" << (instance_ ? 's' : 'p') << ");";
578 out << "class_" << (replace ? "replace" : "add") << "Method($cy" << (instance_ ? 'c' : 'm') << ",$cyn,";
579 out << "new Functor(function(self,_cmd";
580 for (CYMessageParameter *parameter(parameter_); parameter != NULL; parameter = parameter->next_)
581 if (parameter->name_ != NULL)
582 out << ',' << *parameter->name_;
583 out << "){return function(){";
584 if (body_ != NULL)
585 body_->Multiple(out);
586 out << "}.call(self);},$cyt),$cyt);";
587 }
588
589 void CYNew::Output(CYOutput &out, CYFlags flags) const {
590 out << "new" << ' ';
591 CYFlags jacks(CYNoCall | CYCenter(flags));
592 constructor_->Output(out, Precedence(), jacks);
593 if (arguments_ != NULL)
594 out << '(' << *arguments_ << ')';
595 }
596
597 void CYNull::Output(CYOutput &out, CYFlags flags) const {
598 CYWord::Output(out);
599 }
600
601 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
602 char value[32];
603 sprintf(value, "%.17g", Value());
604 out << value;
605 }
606
607 void CYNumber::PropertyName(CYOutput &out) const {
608 Output(out, CYNoFlags);
609 }
610
611 void CYObject::Output(CYOutput &out, CYFlags flags) const {
612 bool protect((flags & CYNoBrace) != 0);
613 if (protect)
614 out << '(';
615 out << '{';
616 out << property_;
617 out << '}';
618 if (protect)
619 out << ')';
620 }
621
622 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
623 lhs_->Output(out, Precedence(), CYLeft(flags));
624 out << Operator();
625 }
626
627 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
628 const char *name(Operator());
629 out << name;
630 if (Alphabetic())
631 out << ' ';
632 rhs_->Output(out, Precedence(), CYRight(flags));
633 }
634
635 void CYProperty::Output(CYOutput &out) const {
636 name_->PropertyName(out);
637 out << ':' << ' ';
638 value_->Output(out, CYPA, CYNoFlags);
639 if (next_ != NULL)
640 out << ',' << ' ' << *next_;
641 }
642
643 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
644 out << Value();
645 }
646
647 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
648 out << "return" << value_ << ';';
649 }
650
651 void CYSelector::Output(CYOutput &out, CYFlags flags) const {
652 out << "new Selector(\"";
653 if (name_ != NULL)
654 name_->Output(out);
655 out << "\")";
656 }
657
658 void CYSelectorPart::Output(CYOutput &out) const {
659 out << name_;
660 if (value_)
661 out << ':';
662 out << next_;
663 }
664
665 void CYSend::Output(CYOutput &out, CYFlags flags) const {
666 out << "objc_msgSend(";
667 self_->Output(out, CYPA, CYNoFlags);
668 out << ',';
669 std::ostringstream name;
670 for (CYArgument *argument(arguments_); argument != NULL; argument = argument->next_)
671 if (argument->name_ != NULL) {
672 name << *argument->name_;
673 if (argument->value_ != NULL)
674 name << ':';
675 }
676 out.out_ << reinterpret_cast<void *>(sel_registerName(name.str().c_str()));
677 for (CYArgument *argument(arguments_); argument != NULL; argument = argument->next_)
678 if (argument->value_ != NULL) {
679 out << ',';
680 argument->value_->Output(out, CYPA, CYNoFlags);
681 }
682 out << ')';
683 }
684
685 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
686 bool first(true);
687 for (const CYStatement *next(this); next != NULL; next = next->next_) {
688 bool last(next->next_ == NULL);
689 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYCenter(flags) : CYRight(flags));
690 first = false;
691 out << '\t';
692 next->Output(out, jacks);
693 out << '\n';
694 }
695 }
696
697 bool CYStatement::Single(CYOutput &out, CYFlags flags) const {
698 if (next_ != NULL) {
699 out << ' ' << '{' << '\n';
700 ++out.indent_;
701 Multiple(out);
702 --out.indent_;
703 out << '\t' << '}';
704 return false;
705 } else {
706 for (CYLabel *label(labels_); label != NULL; label = label->next_)
707 out << ' ' << *label->name_ << ':';
708 out << '\n';
709 ++out.indent_;
710 out << '\t';
711 Output(out, flags);
712 out << '\n';
713 --out.indent_;
714 return true;
715 }
716 }
717
718 void CYString::Output(CYOutput &out, CYFlags flags) const {
719 unsigned quot(0), apos(0);
720 for (const char *value(value_), *end(value_ + size_); value != end; ++value)
721 if (*value == '"')
722 ++quot;
723 else if (*value == '\'')
724 ++apos;
725
726 bool single(quot > apos);
727
728 std::ostringstream str;
729
730 str << (single ? '\'' : '"');
731 for (const char *value(value_), *end(value_ + size_); value != end; ++value)
732 switch (*value) {
733 case '\\': str << "\\\\"; break;
734 case '\b': str << "\\b"; break;
735 case '\f': str << "\\f"; break;
736 case '\n': str << "\\n"; break;
737 case '\r': str << "\\r"; break;
738 case '\t': str << "\\t"; break;
739 case '\v': str << "\\v"; break;
740
741 case '"':
742 if (!single)
743 str << "\\\"";
744 else goto simple;
745 break;
746
747 case '\'':
748 if (single)
749 str << "\\'";
750 else goto simple;
751 break;
752
753 default:
754 if (*value < 0x20 || *value >= 0x7f)
755 str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(*value);
756 else simple:
757 str << *value;
758 }
759 str << (single ? '\'' : '"');
760
761 out << str.str().c_str();
762 }
763
764 void CYString::PropertyName(CYOutput &out) const {
765 if (const char *word = Word())
766 out << word;
767 else
768 out << *this;
769 }
770
771 const char *CYString::Word() const {
772 if (size_ == 0 || !WordStartRange_[value_[0]])
773 return NULL;
774 for (size_t i(1); i != size_; ++i)
775 if (!WordEndRange_[value_[i]])
776 return NULL;
777 const char *value(Value());
778 // XXX: we should probably include the full ECMAScript3+5 list.
779 static const char *reserveds[] = {"class", "const", "enum", "export", "extends", "import", "super", NULL};
780 for (const char **reserved(reserveds); *reserved != NULL; ++reserved)
781 if (strcmp(*reserved, value) == 0)
782 return NULL;
783 return value;
784 }
785
786 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
787 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{';
788 out << clauses_;
789 out << '}';
790 }
791
792 void CYThis::Output(CYOutput &out, CYFlags flags) const {
793 CYWord::Output(out);
794 }
795
796 void CYThrow::Output(CYOutput &out, CYFlags flags) const {
797 out << "throw" << value_ << ';';
798 }
799
800 void CYTry::Output(CYOutput &out, CYFlags flags) const {
801 out << "try" << ' ' << '{';
802 if (code_ != NULL)
803 code_->Multiple(out);
804 out << '}';
805 out << catch_;
806 out << finally_;
807 }
808
809 void CYVar::Output(CYOutput &out, CYFlags flags) const {
810 out << "var";
811 declarations_->Output(out, flags);
812 out << ';';
813 }
814
815 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
816 out << *name_;
817 }
818
819 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
820 out << "while" << '(' << *test_ << ')';
821 code_->Single(out, CYRight(flags));
822 }
823
824 void CYWith::Output(CYOutput &out, CYFlags flags) const {
825 out << "with" << '(' << *scope_ << ')';
826 code_->Single(out, CYRight(flags));
827 }
828
829 void CYWord::ClassName(CYOutput &out, bool object) const {
830 if (object)
831 out << "objc_getClass(";
832 out << '"' << Value() << '"';
833 if (object)
834 out << ')';
835 }
836
837 void CYWord::Output(CYOutput &out) const {
838 out << Value();
839 }
840
841 void CYWord::PropertyName(CYOutput &out) const {
842 Output(out);
843 }