]> git.saurik.com Git - cycript.git/blob - Output.cpp
Fix off-by-one in syntax error output (infinite loop).
[cycript.git] / Output.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2010 Jay Freeman (saurik)
3 */
4
5 /* GNU Lesser General Public License, Version 3 {{{ */
6 /*
7 * Cycript is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * Cycript is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include "cycript.hpp"
23 #include "Parser.hpp"
24
25 #include <sstream>
26
27 _finline CYFlags operator ~(CYFlags rhs) {
28 return static_cast<CYFlags>(~static_cast<unsigned>(rhs));
29 }
30
31 _finline CYFlags operator &(CYFlags lhs, CYFlags rhs) {
32 return static_cast<CYFlags>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs));
33 }
34
35 _finline CYFlags operator |(CYFlags lhs, CYFlags rhs) {
36 return static_cast<CYFlags>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs));
37 }
38
39 _finline CYFlags &operator |=(CYFlags &lhs, CYFlags rhs) {
40 return lhs = lhs | rhs;
41 }
42
43 _finline CYFlags CYLeft(CYFlags flags) {
44 return flags & ~(CYNoDangle | CYNoInteger);
45 }
46
47 _finline CYFlags CYRight(CYFlags flags) {
48 return flags & ~CYNoBF;
49 }
50
51 _finline CYFlags CYCenter(CYFlags flags) {
52 return CYLeft(CYRight(flags));
53 }
54
55 void CYOutput::Terminate() {
56 out_ << ';';
57 mode_ = NoMode;
58 }
59
60 CYOutput &CYOutput::operator <<(char rhs) {
61 if (rhs == ' ' || rhs == '\n')
62 if (pretty_)
63 out_ << rhs;
64 else goto done;
65 else if (rhs == '\t')
66 if (pretty_)
67 for (unsigned i(0); i != indent_; ++i)
68 out_ << " ";
69 else goto done;
70 else if (rhs == '\r') {
71 if (right_) {
72 out_ << '\n';
73 right_ = false;
74 } goto done;
75 } else goto work;
76
77 right_ = true;
78 mode_ = NoMode;
79 goto done;
80
81 work:
82 if (mode_ == Terminated && rhs != '}') {
83 right_ = true;
84 out_ << ';';
85 }
86
87 if (rhs == ';') {
88 if (pretty_)
89 goto none;
90 else {
91 mode_ = Terminated;
92 goto done;
93 }
94 } else if (rhs == '+') {
95 if (mode_ == NoPlus)
96 out_ << ' ';
97 mode_ = NoPlus;
98 } else if (rhs == '-') {
99 if (mode_ == NoHyphen)
100 out_ << ' ';
101 mode_ = NoHyphen;
102 } else if (WordEndRange_[rhs]) {
103 if (mode_ == NoLetter)
104 out_ << ' ';
105 mode_ = NoLetter;
106 } else none:
107 mode_ = NoMode;
108
109 right_ = true;
110 out_ << rhs;
111 done:
112 return *this;
113 }
114
115 CYOutput &CYOutput::operator <<(const char *rhs) {
116 size_t size(strlen(rhs));
117
118 if (size == 1)
119 return *this << *rhs;
120
121 if (mode_ == Terminated)
122 out_ << ';';
123 else if (
124 mode_ == NoPlus && *rhs == '+' ||
125 mode_ == NoHyphen && *rhs == '-' ||
126 mode_ == NoLetter && WordEndRange_[*rhs]
127 )
128 out_ << ' ';
129
130 if (WordEndRange_[rhs[size - 1]])
131 mode_ = NoLetter;
132 else
133 mode_ = NoMode;
134
135 right_ = true;
136 out_ << rhs;
137 return *this;
138 }
139
140 void CYArgument::Output(CYOutput &out) const {
141 if (name_ != NULL) {
142 out << *name_;
143 if (value_ != NULL)
144 out << ':' << ' ';
145 }
146 if (value_ != NULL)
147 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
148 if (next_ != NULL) {
149 if (next_->name_ == NULL)
150 out << ',';
151 out << ' ' << *next_;
152 }
153 }
154
155 void CYArray::Output(CYOutput &out, CYFlags flags) const {
156 out << '[' << elements_ << ']';
157 }
158
159 void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
160 out << '[' << *expression_ << ' ' << *comprehensions_ << ']';
161 }
162
163 void CYAssignment::Output(CYOutput &out, CYFlags flags) const {
164 lhs_->Output(out, Precedence() - 1, CYLeft(flags) | CYNoRightHand);
165 out << ' ' << Operator() << ' ';
166 rhs_->Output(out, Precedence(), CYRight(flags));
167 }
168
169 void CYBlock::Output(CYOutput &out) const {
170 out << '{' << '\n';
171 ++out.indent_;
172 if (statements_ != NULL)
173 statements_->Multiple(out);
174 --out.indent_;
175 out << '\t' << '}';
176 }
177
178 void CYBlock::Output(CYOutput &out, CYFlags flags) const {
179 if (statements_ == NULL)
180 out.Terminate();
181 else if (statements_->next_ == NULL)
182 statements_->Single(out, flags);
183 else
184 Output(out);
185 }
186
187 void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
188 out << (Value() ? "true" : "false");
189 }
190
191 void CYBreak::Output(CYOutput &out, CYFlags flags) const {
192 out << "break";
193 if (label_ != NULL)
194 out << ' ' << *label_;
195 out << ';';
196 }
197
198 void CYCall::Output(CYOutput &out, CYFlags flags) const {
199 bool protect((flags & CYNoCall) != 0);
200 if (protect)
201 out << '(';
202 function_->Output(out, Precedence(), protect ? CYNoFlags : flags);
203 out << '(' << arguments_ << ')';
204 if (protect)
205 out << ')';
206 }
207
208 namespace cy {
209 namespace Syntax {
210
211 void Catch::Output(CYOutput &out) const {
212 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ' << code_;
213 }
214
215 } }
216
217 void CYComment::Output(CYOutput &out, CYFlags flags) const {
218 out << '\r';
219 out.out_ << value_;
220 out.right_ = true;
221 out << '\r';
222 }
223
224 void CYCompound::Output(CYOutput &out, CYFlags flags) const {
225 if (CYExpression *expression = expressions_)
226 if (CYExpression *next = expression->next_) {
227 expression->Output(out, CYLeft(flags));
228 CYFlags center(CYCenter(flags));
229 while (next != NULL) {
230 expression = next;
231 out << ',' << ' ';
232 next = expression->next_;
233 CYFlags right(next != NULL ? center : CYRight(flags));
234 expression->Output(out, right);
235 }
236 } else
237 expression->Output(out, flags);
238 }
239
240 void CYCondition::Output(CYOutput &out, CYFlags flags) const {
241 test_->Output(out, Precedence() - 1, CYLeft(flags));
242 out << ' ' << '?' << ' ';
243 if (true_ != NULL)
244 true_->Output(out, CYAssign::Precedence_, CYNoFlags);
245 out << ' ' << ':' << ' ';
246 false_->Output(out, CYAssign::Precedence_, CYRight(flags));
247 }
248
249 void CYContinue::Output(CYOutput &out, CYFlags flags) const {
250 out << "continue";
251 if (label_ != NULL)
252 out << ' ' << *label_;
253 out << ';';
254 }
255
256 void CYClause::Output(CYOutput &out) const {
257 if (case_ != NULL)
258 out << "case" << ' ' << *case_;
259 else
260 out << "default";
261 out << ':' << '\n';
262 if (statements_ != NULL)
263 statements_->Multiple(out);
264 out << next_;
265 }
266
267 const char *CYDeclaration::ForEachIn() const {
268 return identifier_->Word();
269 }
270
271 void CYDeclaration::ForIn(CYOutput &out, CYFlags flags) const {
272 out << "var";
273 Output(out, CYRight(flags));
274 }
275
276 void CYDeclaration::Output(CYOutput &out, CYFlags flags) const {
277 out << *identifier_;
278 //out.out_ << ':' << identifier_->usage_ << '#' << identifier_->offset_;
279 if (initialiser_ != NULL) {
280 out << ' ' << '=' << ' ';
281 initialiser_->Output(out, CYAssign::Precedence_, CYRight(flags));
282 }
283 }
284
285 void CYDeclarations::For(CYOutput &out) const {
286 out << "var";
287 Output(out, CYNoIn);
288 }
289
290 void CYDeclarations::Output(CYOutput &out) const {
291 Output(out, CYNoFlags);
292 }
293
294 void CYDeclarations::Output(CYOutput &out, CYFlags flags) const {
295 const CYDeclarations *declaration(this);
296 bool first(true);
297 output:
298 CYDeclarations *next(declaration->next_);
299 CYFlags jacks(first ? CYLeft(flags) : next == NULL ? CYRight(flags) : CYCenter(flags));
300 first = false;
301 declaration->declaration_->Output(out, jacks);
302
303 if (next != NULL) {
304 out << ',' << ' ';
305 declaration = next;
306 goto output;
307 }
308 }
309
310 void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
311 object_->Output(out, Precedence(), CYLeft(flags) | CYNoInteger);
312 if (const char *word = property_->Word())
313 out << '.' << word;
314 else
315 out << '[' << *property_ << ']';
316 }
317
318 void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
319 out << "do";
320 code_->Single(out, CYCenter(flags));
321 out << "while" << ' ' << '(' << *test_ << ')';
322 }
323
324 void CYElement::Output(CYOutput &out) const {
325 if (value_ != NULL)
326 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
327 if (next_ != NULL || value_ == NULL) {
328 out << ',';
329 if (next_ != NULL && next_->value_ != NULL)
330 out << ' ';
331 }
332 if (next_ != NULL)
333 next_->Output(out);
334 }
335
336 void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
337 out.Terminate();
338 }
339
340 void CYExpress::Output(CYOutput &out, CYFlags flags) const {
341 expression_->Output(out, flags | CYNoBF);
342 out << ';';
343 }
344
345 void CYExpression::ClassName(CYOutput &out, bool object) const {
346 Output(out, CYAssign::Precedence_, CYNoFlags);
347 }
348
349 const char *CYExpression::ForEachIn() const {
350 return NULL;
351 }
352
353 void CYExpression::For(CYOutput &out) const {
354 Output(out, CYNoIn);
355 }
356
357 void CYExpression::ForIn(CYOutput &out, CYFlags flags) const {
358 Output(out, flags | CYNoRightHand);
359 }
360
361 void CYExpression::Output(CYOutput &out) const {
362 Output(out, CYNoFlags);
363 }
364
365 void CYExpression::Output(CYOutput &out, unsigned precedence, CYFlags flags) const {
366 if (precedence < Precedence() || (flags & CYNoRightHand) != 0 && RightHand())
367 out << '(' << *this << ')';
368 else
369 Output(out, flags);
370 }
371
372 void CYFinally::Output(CYOutput &out) const {
373 out << ' ' << "finally" << ' ' << code_;
374 }
375
376 void CYFor::Output(CYOutput &out, CYFlags flags) const {
377 out << "for" << ' ' << '(';
378 if (initialiser_ != NULL)
379 initialiser_->For(out);
380 out.Terminate();
381 if (test_ != NULL)
382 out << ' ';
383 out << test_;
384 out.Terminate();
385 if (increment_ != NULL)
386 out << ' ';
387 out << increment_;
388 out << ')';
389 code_->Single(out, CYRight(flags));
390 }
391
392 void CYForEachIn::Output(CYOutput &out, CYFlags flags) const {
393 out << "for" << ' ' << "each" << ' ' << '(';
394 initialiser_->ForIn(out, CYNoIn);
395 out << "in" << *set_ << ')';
396 code_->Single(out, CYRight(flags));
397 }
398
399 void CYForEachInComprehension::Output(CYOutput &out) const {
400 out << "for" << ' ' << "each" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')' << next_;
401 }
402
403 void CYForIn::Output(CYOutput &out, CYFlags flags) const {
404 out << "for" << ' ' << '(';
405 if (initialiser_ != NULL)
406 initialiser_->ForIn(out, CYNoIn);
407 out << "in" << *set_ << ')';
408 code_->Single(out, CYRight(flags));
409 }
410
411 void CYForInComprehension::Output(CYOutput &out) const {
412 out << "for" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')';
413 }
414
415 void CYFunction::Output(CYOutput &out, CYFlags flags) const {
416 // XXX: one could imagine using + here to save a byte
417 bool protect((flags & CYNoFunction) != 0);
418 if (protect)
419 out << '(';
420 out << "function";
421 if (name_ != NULL)
422 out << ' ' << *name_;
423 out << '(' << parameters_ << ')';
424 out << ' ' << code_;
425 if (protect)
426 out << ')';
427 }
428
429 void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
430 CYFunction::Output(out, flags);
431 }
432
433 void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
434 CYFunction::Output(out, flags);
435 }
436
437 void CYFunctionParameter::Output(CYOutput &out) const {
438 out << *name_;
439 if (next_ != NULL)
440 out << ',' << ' ' << *next_;
441 }
442
443 const char *CYIdentifier::Word() const {
444 return replace_ == NULL || replace_ == this ? CYWord::Word() : replace_->Word();
445 }
446
447 void CYIf::Output(CYOutput &out, CYFlags flags) const {
448 bool protect(false);
449 if (false_ == NULL && (flags & CYNoDangle) != 0) {
450 protect = true;
451 out << '{';
452 }
453
454 out << "if" << ' ' << '(' << *test_ << ')';
455
456 CYFlags right(protect ? CYNoFlags : CYRight(flags));
457
458 CYFlags jacks(CYNoDangle);
459 if (false_ == NULL)
460 jacks |= right;
461 else
462 jacks |= protect ? CYNoFlags : CYCenter(flags);
463
464 true_->Single(out, jacks);
465
466 if (false_ != NULL) {
467 out << '\t' << "else";
468 false_->Single(out, right);
469 }
470
471 if (protect)
472 out << '}';
473 }
474
475 void CYIfComprehension::Output(CYOutput &out) const {
476 out << "if" << ' ' << '(' << *test_ << ')' << next_;
477 }
478
479 void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
480 object_->Output(out, Precedence(), CYLeft(flags));
481 if (const char *word = property_->Word())
482 out << "->" << word;
483 else
484 out << "->" << '[' << *property_ << ']';
485 }
486
487 void CYInfix::Output(CYOutput &out, CYFlags flags) const {
488 const char *name(Operator());
489 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
490 if (protect)
491 out << '(';
492 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
493 lhs_->Output(out, Precedence(), left);
494 out << ' ' << name << ' ';
495 CYFlags right(protect ? CYNoFlags : CYRight(flags));
496 rhs_->Output(out, Precedence() - 1, right);
497 if (protect)
498 out << ')';
499 }
500
501 void CYLabel::Output(CYOutput &out, CYFlags flags) const {
502 out << *name_ << ':' << ' ';
503 statement_->Single(out, CYRight(flags));
504 }
505
506 void CYLet::Output(CYOutput &out, CYFlags flags) const {
507 out << "let" << ' ' << '(' << *declarations_ << ')' << ' ' << code_;
508 }
509
510 namespace cy {
511 namespace Syntax {
512
513 void New::Output(CYOutput &out, CYFlags flags) const {
514 out << "new" << ' ';
515 CYFlags jacks(CYNoCall | CYCenter(flags));
516 constructor_->Output(out, Precedence(), jacks);
517 if (arguments_ != NULL)
518 out << '(' << *arguments_ << ')';
519 }
520
521 } }
522
523 void CYNull::Output(CYOutput &out, CYFlags flags) const {
524 CYWord::Output(out);
525 }
526
527 void CYNumber::Output(CYOutput &out, CYFlags flags) const {
528 std::ostringstream str;
529 CYNumerify(str, Value());
530 std::string value(str.str());
531 out << value.c_str();
532 // XXX: this should probably also handle hex conversions and exponents
533 if ((flags & CYNoInteger) != 0 && value.find('.') == std::string::npos)
534 out << '.';
535 }
536
537 void CYNumber::PropertyName(CYOutput &out) const {
538 Output(out, CYNoFlags);
539 }
540
541 void CYObject::Output(CYOutput &out, CYFlags flags) const {
542 bool protect((flags & CYNoBrace) != 0);
543 if (protect)
544 out << '(';
545 out << '{' << '\n';
546 ++out.indent_;
547 out << properties_;
548 --out.indent_;
549 out << '\t' << '}';
550 if (protect)
551 out << ')';
552 }
553
554 void CYOptionalFunctionParameter::Output(CYOutput &out) const {
555 out << *name_ << '=';
556 initializer_->Output(out, CYAssign::Precedence_, CYNoFlags);
557 if (next_ != NULL)
558 out << ',' << ' ' << *next_;
559 }
560
561 void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
562 lhs_->Output(out, Precedence(), CYLeft(flags));
563 out << Operator();
564 }
565
566 void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
567 const char *name(Operator());
568 out << name;
569 if (Alphabetic())
570 out << ' ';
571 rhs_->Output(out, Precedence(), CYRight(flags));
572 }
573
574 void CYProgram::Output(CYOutput &out) const {
575 if (statements_ != NULL)
576 statements_->Multiple(out);
577 }
578
579 void CYProperty::Output(CYOutput &out) const {
580 out << '\t';
581 name_->PropertyName(out);
582 out << ':' << ' ';
583 value_->Output(out, CYAssign::Precedence_, CYNoFlags);
584 if (next_ != NULL)
585 out << ',' << '\n' << *next_;
586 else
587 out << '\n';
588 }
589
590 void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
591 out << Value();
592 }
593
594 void CYReturn::Output(CYOutput &out, CYFlags flags) const {
595 out << "return";
596 if (value_ != NULL)
597 out << ' ' << *value_;
598 out << ';';
599 }
600
601 void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const {
602 call_->Output(out, CYLeft(flags));
603 out << ' ';
604 proc_->Output(out, CYRight(flags));
605 }
606
607 void CYRubyProc::Output(CYOutput &out, CYFlags flags) const {
608 // XXX: this is not outputting the parameters
609 out << code_;
610 }
611
612 void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
613 bool first(true);
614 CYForEach (next, this) {
615 bool last(next->next_ == NULL);
616 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYRight(flags) : CYCenter(flags));
617 first = false;
618 out << '\t';
619 next->Output(out, jacks);
620 out << '\n';
621 }
622 }
623
624 void CYStatement::Single(CYOutput &out, CYFlags flags) const {
625 _assert(next_ == NULL);
626 out << '\n';
627 ++out.indent_;
628 out << '\t';
629 Output(out, flags);
630 out << '\n';
631 --out.indent_;
632 }
633
634 void CYString::Output(CYOutput &out, CYFlags flags) const {
635 std::ostringstream str;
636 CYStringify(str, value_, size_);
637 out << str.str().c_str();
638 }
639
640 void CYString::PropertyName(CYOutput &out) const {
641 if (const char *word = Word())
642 out << word;
643 else
644 out << *this;
645 }
646
647 static const char *Reserved_[] = {
648 "false", "null", "true",
649
650 "break", "case", "catch", "continue", "default",
651 "delete", "do", "else", "finally", "for", "function",
652 "if", "in", "instanceof", "new", "return", "switch",
653 "this", "throw", "try", "typeof", "var", "void",
654 "while", "with",
655
656 "debugger", "const",
657
658 "class", "enum", "export", "extends", "import", "super",
659
660 "abstract", "boolean", "byte", "char", "double", "final",
661 "float", "goto", "int", "long", "native", "short",
662 "synchronized", "throws", "transient", "volatile",
663
664 "let", "yield",
665
666 NULL
667 };
668
669 const char *CYString::Word() const {
670 if (size_ == 0 || !WordStartRange_[value_[0]])
671 return NULL;
672 for (size_t i(1); i != size_; ++i)
673 if (!WordEndRange_[value_[i]])
674 return NULL;
675 const char *value(Value());
676 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
677 if (strcmp(*reserved, value) == 0)
678 return NULL;
679 return value;
680 }
681
682 void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
683 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{';
684 out << clauses_;
685 out << '}';
686 }
687
688 void CYThis::Output(CYOutput &out, CYFlags flags) const {
689 CYWord::Output(out);
690 }
691
692 namespace cy {
693 namespace Syntax {
694
695 void Throw::Output(CYOutput &out, CYFlags flags) const {
696 out << "throw";
697 if (value_ != NULL)
698 out << ' ' << *value_;
699 out << ';';
700 }
701
702 void Try::Output(CYOutput &out, CYFlags flags) const {
703 out << "try" << ' ' << code_ << catch_ << finally_;
704 }
705
706 } }
707
708 void CYVar::Output(CYOutput &out, CYFlags flags) const {
709 out << "var";
710 declarations_->Output(out, flags);
711 out << ';';
712 }
713
714 void CYVariable::Output(CYOutput &out, CYFlags flags) const {
715 out << *name_;
716 }
717
718 void CYWhile::Output(CYOutput &out, CYFlags flags) const {
719 out << "while" << '(' << *test_ << ')';
720 code_->Single(out, CYRight(flags));
721 }
722
723 void CYWith::Output(CYOutput &out, CYFlags flags) const {
724 out << "with" << '(' << *scope_ << ')';
725 code_->Single(out, CYRight(flags));
726 }
727
728 void CYWord::ClassName(CYOutput &out, bool object) const {
729 if (object)
730 out << "objc_getClass(";
731 out << '"' << Word() << '"';
732 if (object)
733 out << ')';
734 }
735
736 void CYWord::Output(CYOutput &out) const {
737 out << Word();
738 if (out.options_.verbose_)
739 out.out_ << '@' << this;
740 }
741
742 void CYWord::PropertyName(CYOutput &out) const {
743 Output(out);
744 }
745
746 const char *CYWord::Word() const {
747 return word_;
748 }