]> git.saurik.com Git - cycript.git/blame_incremental - Output.cpp
Finally got this damned thing actually executing JavaScript on Linux.
[cycript.git] / Output.cpp
... / ...
CommitLineData
1/* Cycript - Remove Execution Server and Disassembler
2 * Copyright (C) 2009 Jay Freeman (saurik)
3*/
4
5/* Modified BSD License {{{ */
6/*
7 * Redistribution and use in source and binary
8 * forms, with or without modification, are permitted
9 * provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the
12 * above copyright notice, this list of conditions
13 * and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the
15 * above copyright notice, this list of conditions
16 * and the following disclaimer in the documentation
17 * and/or other materials provided with the
18 * distribution.
19 * 3. The name of the author may not be used to endorse
20 * or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
25 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37*/
38/* }}} */
39
40#include "cycript.hpp"
41#include "Parser.hpp"
42
43#include <sstream>
44
45_finline CYFlags operator ~(CYFlags rhs) {
46 return static_cast<CYFlags>(~static_cast<unsigned>(rhs));
47}
48
49_finline CYFlags operator &(CYFlags lhs, CYFlags rhs) {
50 return static_cast<CYFlags>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs));
51}
52
53_finline CYFlags operator |(CYFlags lhs, CYFlags rhs) {
54 return static_cast<CYFlags>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs));
55}
56
57_finline CYFlags &operator |=(CYFlags &lhs, CYFlags rhs) {
58 return lhs = lhs | rhs;
59}
60
61_finline CYFlags CYLeft(CYFlags flags) {
62 return flags & ~CYNoDangle;
63}
64
65_finline CYFlags CYRight(CYFlags flags) {
66 return flags & ~CYNoBF;
67}
68
69_finline CYFlags CYCenter(CYFlags flags) {
70 return CYLeft(CYRight(flags));
71}
72
73void CYOutput::Terminate() {
74 out_ << ';';
75 mode_ = NoMode;
76}
77
78CYOutput &CYOutput::operator <<(char rhs) {
79 if (rhs == ' ' || rhs == '\n')
80 if (pretty_)
81 out_ << rhs;
82 else goto done;
83 else if (rhs == '\t')
84 if (pretty_)
85 for (unsigned i(0); i != indent_; ++i)
86 out_ << " ";
87 else goto done;
88 else goto work;
89
90 mode_ = NoMode;
91 goto done;
92
93 work:
94 if (mode_ == Terminated && rhs != '}')
95 out_ << ';';
96
97 if (rhs == ';') {
98 if (pretty_)
99 goto none;
100 else {
101 mode_ = Terminated;
102 goto done;
103 }
104 } else if (rhs == '+') {
105 if (mode_ == NoPlus)
106 out_ << ' ';
107 mode_ = NoPlus;
108 } else if (rhs == '-') {
109 if (mode_ == NoHyphen)
110 out_ << ' ';
111 mode_ = NoHyphen;
112 } else if (WordEndRange_[rhs]) {
113 if (mode_ == NoLetter)
114 out_ << ' ';
115 mode_ = NoLetter;
116 } else none:
117 mode_ = NoMode;
118
119 out_ << rhs;
120 done:
121 return *this;
122}
123
124CYOutput &CYOutput::operator <<(const char *rhs) {
125 size_t size(strlen(rhs));
126
127 if (size == 1)
128 return *this << *rhs;
129
130 if (mode_ == Terminated)
131 out_ << ';';
132 else if (
133 mode_ == NoPlus && *rhs == '+' ||
134 mode_ == NoHyphen && *rhs == '-' ||
135 mode_ == NoLetter && WordEndRange_[*rhs]
136 )
137 out_ << ' ';
138
139 if (WordEndRange_[rhs[size - 1]])
140 mode_ = NoLetter;
141 else
142 mode_ = NoMode;
143
144 out_ << rhs;
145 return *this;
146}
147
148void CYArgument::Output(CYOutput &out) const {
149 if (name_ != NULL) {
150 out << *name_;
151 if (value_ != NULL)
152 out << ':' << ' ';
153 }
154 if (value_ != NULL)
155 value_->Output(out, CYPA, CYNoFlags);
156 if (next_ != NULL) {
157 if (next_->name_ == NULL)
158 out << ',';
159 out << ' ' << *next_;
160 }
161}
162
163void CYArray::Output(CYOutput &out, CYFlags flags) const {
164 out << '[' << elements_ << ']';
165}
166
167void CYArrayComprehension::Output(CYOutput &out, CYFlags flags) const {
168 out << '[' << *expression_ << ' ' << *comprehensions_ << ']';
169}
170
171void CYAssignment::Output(CYOutput &out, CYFlags flags) const {
172 lhs_->Output(out, Precedence() - 1, CYLeft(flags) | CYNoRightHand);
173 out << ' ' << Operator() << ' ';
174 rhs_->Output(out, Precedence(), CYRight(flags));
175}
176
177void CYBlock::Output(CYOutput &out) const {
178 out << '{' << '\n';
179 ++out.indent_;
180 if (statements_ != NULL)
181 statements_->Multiple(out);
182 --out.indent_;
183 out << '\t' << '}';
184}
185
186void CYBlock::Output(CYOutput &out, CYFlags flags) const {
187 if (statements_ == NULL)
188 out.Terminate();
189 else if (statements_->next_ == NULL)
190 statements_->Single(out, flags);
191 else
192 Output(out);
193}
194
195void CYBoolean::Output(CYOutput &out, CYFlags flags) const {
196 out << (Value() ? "true" : "false");
197}
198
199void CYBreak::Output(CYOutput &out, CYFlags flags) const {
200 out << "break";
201 if (label_ != NULL)
202 out << ' ' << *label_;
203 out << ';';
204}
205
206void CYCall::Output(CYOutput &out, CYFlags flags) const {
207 bool protect((flags & CYNoCall) != 0);
208 if (protect)
209 out << '(';
210 function_->Output(out, Precedence(), protect ? CYNoFlags : flags);
211 out << '(' << arguments_ << ')';
212 if (protect)
213 out << ')';
214}
215
216namespace cy {
217namespace Syntax {
218
219void Catch::Output(CYOutput &out) const {
220 out << ' ' << "catch" << ' ' << '(' << *name_ << ')' << ' ' << code_;
221}
222
223} }
224
225void CYCompound::Output(CYOutput &out, CYFlags flags) const {
226 if (CYExpression *expression = expressions_)
227 if (CYExpression *next = expression->next_) {
228 expression->Output(out, CYLeft(flags));
229 CYFlags center(CYCenter(flags));
230 while (next != NULL) {
231 expression = next;
232 out << ',' << ' ';
233 next = expression->next_;
234 CYFlags right(next != NULL ? center : CYRight(flags));
235 expression->Output(out, right);
236 }
237 } else
238 expression->Output(out, flags);
239}
240
241void CYCondition::Output(CYOutput &out, CYFlags flags) const {
242 test_->Output(out, Precedence() - 1, CYLeft(flags));
243 out << ' ' << '?' << ' ';
244 if (true_ != NULL)
245 true_->Output(out, CYPA, CYNoFlags);
246 out << ' ' << ':' << ' ';
247 false_->Output(out, CYPA, CYRight(flags));
248}
249
250void CYContinue::Output(CYOutput &out, CYFlags flags) const {
251 out << "continue";
252 if (label_ != NULL)
253 out << ' ' << *label_;
254 out << ';';
255}
256
257void CYClause::Output(CYOutput &out) const {
258 if (case_ != NULL)
259 out << "case" << ' ' << *case_;
260 else
261 out << "default";
262 out << ':' << '\n';
263 if (statements_ != NULL)
264 statements_->Multiple(out);
265 out << next_;
266}
267
268const char *CYDeclaration::ForEachIn() const {
269 return identifier_->Value();
270}
271
272void CYDeclaration::ForIn(CYOutput &out, CYFlags flags) const {
273 out << "var";
274 Output(out, CYRight(flags));
275}
276
277void CYDeclaration::Output(CYOutput &out, CYFlags flags) const {
278 out << *identifier_;
279 if (initialiser_ != NULL) {
280 out << ' ' << '=' << ' ';
281 initialiser_->Output(out, CYPA, CYRight(flags));
282 }
283}
284
285void CYDeclarations::For(CYOutput &out) const {
286 out << "var";
287 Output(out, CYNoIn);
288}
289
290void CYDeclarations::Output(CYOutput &out) const {
291 Output(out, CYNoFlags);
292}
293
294void 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
310void CYDirectMember::Output(CYOutput &out, CYFlags flags) const {
311 object_->Output(out, Precedence(), CYLeft(flags));
312 if (const char *word = property_->Word())
313 out << '.' << word;
314 else
315 out << '[' << *property_ << ']';
316}
317
318void CYDoWhile::Output(CYOutput &out, CYFlags flags) const {
319 out << "do";
320 code_->Single(out, CYCenter(flags));
321 out << "while" << ' ' << '(' << *test_ << ')';
322}
323
324void CYElement::Output(CYOutput &out) const {
325 if (value_ != NULL)
326 value_->Output(out, CYPA, 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
336void CYEmpty::Output(CYOutput &out, CYFlags flags) const {
337 out.Terminate();
338}
339
340void CYExpress::Output(CYOutput &out, CYFlags flags) const {
341 expression_->Output(out, flags | CYNoBF);
342 out << ';';
343}
344
345void CYExpression::ClassName(CYOutput &out, bool object) const {
346 Output(out, CYPA, CYNoFlags);
347}
348
349const char *CYExpression::ForEachIn() const {
350 return NULL;
351}
352
353void CYExpression::For(CYOutput &out) const {
354 Output(out, CYNoIn);
355}
356
357void CYExpression::ForIn(CYOutput &out, CYFlags flags) const {
358 Output(out, flags | CYNoRightHand);
359}
360
361void CYExpression::Output(CYOutput &out) const {
362 Output(out, CYNoFlags);
363}
364
365void 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
372void CYFinally::Output(CYOutput &out) const {
373 out << ' ' << "finally" << ' ' << code_;
374}
375
376void CYFor::Output(CYOutput &out, CYFlags flags) const {
377 out << "for" << ' ' << '(';
378 if (initialiser_ != NULL)
379 initialiser_->For(out);
380 out.Terminate();
381 out << test_;
382 out.Terminate();
383 out << increment_;
384 out << ')';
385 code_->Single(out, CYRight(flags));
386}
387
388void CYForEachIn::Output(CYOutput &out, CYFlags flags) const {
389 out << "for" << ' ' << "each" << ' ' << '(';
390 initialiser_->ForIn(out, CYNoIn);
391 out << "in" << *set_ << ')';
392 code_->Single(out, CYRight(flags));
393}
394
395void CYForEachInComprehension::Output(CYOutput &out) const {
396 out << "for" << ' ' << "each" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')' << next_;
397}
398
399void CYForIn::Output(CYOutput &out, CYFlags flags) const {
400 out << "for" << ' ' << '(';
401 initialiser_->ForIn(out, CYNoIn);
402 out << "in" << *set_ << ')';
403 code_->Single(out, CYRight(flags));
404}
405
406void CYForInComprehension::Output(CYOutput &out) const {
407 out << "for" << ' ' << '(' << *name_ << ' ' << "in" << ' ' << *set_ << ')';
408}
409
410void CYFunction::Output(CYOutput &out, CYFlags flags) const {
411 // XXX: one could imagine using + here to save a byte
412 bool protect((flags & CYNoFunction) != 0);
413 if (protect)
414 out << '(';
415 out << "function";
416 if (name_ != NULL)
417 out << ' ' << *name_;
418 out << '(' << parameters_ << ')';
419 out << ' ' << code_;
420 if (protect)
421 out << ')';
422}
423
424void CYFunctionExpression::Output(CYOutput &out, CYFlags flags) const {
425 CYFunction::Output(out, flags);
426}
427
428void CYFunctionStatement::Output(CYOutput &out, CYFlags flags) const {
429 CYFunction::Output(out, flags);
430}
431
432void CYFunctionParameter::Output(CYOutput &out) const {
433 out << *name_;
434 if (next_ != NULL)
435 out << ',' << ' ' << *next_;
436}
437
438void CYIf::Output(CYOutput &out, CYFlags flags) const {
439 bool protect(false);
440 if (false_ == NULL && (flags & CYNoDangle) != 0) {
441 protect = true;
442 out << '{';
443 }
444
445 out << "if" << ' ' << '(' << *test_ << ')';
446
447 CYFlags right(protect ? CYNoFlags : CYRight(flags));
448
449 CYFlags jacks(CYNoDangle);
450 if (false_ == NULL)
451 jacks |= right;
452 else
453 jacks |= protect ? CYNoFlags : CYCenter(flags);
454
455 true_->Single(out, jacks);
456
457 if (false_ != NULL) {
458 out << "else";
459 false_->Single(out, right);
460 }
461
462 if (protect)
463 out << '}';
464}
465
466void CYIfComprehension::Output(CYOutput &out) const {
467 out << "if" << ' ' << '(' << *test_ << ')' << next_;
468}
469
470void CYIndirectMember::Output(CYOutput &out, CYFlags flags) const {
471 object_->Output(out, Precedence(), CYLeft(flags));
472 if (const char *word = property_->Word())
473 out << "->" << word;
474 else
475 out << "->" << '[' << *property_ << ']';
476}
477
478void CYInfix::Output(CYOutput &out, CYFlags flags) const {
479 const char *name(Operator());
480 bool protect((flags & CYNoIn) != 0 && strcmp(name, "in") == 0);
481 if (protect)
482 out << '(';
483 CYFlags left(protect ? CYNoFlags : CYLeft(flags));
484 lhs_->Output(out, Precedence(), left);
485 out << ' ' << name << ' ';
486 CYFlags right(protect ? CYNoFlags : CYRight(flags));
487 rhs_->Output(out, Precedence() - 1, right);
488 if (protect)
489 out << ')';
490}
491
492void CYLabel::Output(CYOutput &out, CYFlags flags) const {
493 out << *name_ << ':' << ' ';
494 statement_->Single(out, CYRight(flags));
495}
496
497void CYLet::Output(CYOutput &out, CYFlags flags) const {
498 out << "let" << ' ' << '(' << *declarations_ << ')' << ' ' << code_;
499}
500
501void CYNew::Output(CYOutput &out, CYFlags flags) const {
502 out << "new" << ' ';
503 CYFlags jacks(CYNoCall | CYCenter(flags));
504 constructor_->Output(out, Precedence(), jacks);
505 if (arguments_ != NULL)
506 out << '(' << *arguments_ << ')';
507}
508
509void CYNull::Output(CYOutput &out, CYFlags flags) const {
510 CYWord::Output(out);
511}
512
513void CYNumber::Output(CYOutput &out, CYFlags flags) const {
514 std::ostringstream str;
515 CYNumerify(str, Value());
516 out << str.str().c_str();
517}
518
519void CYNumber::PropertyName(CYOutput &out) const {
520 Output(out, CYNoFlags);
521}
522
523void CYObject::Output(CYOutput &out, CYFlags flags) const {
524 bool protect((flags & CYNoBrace) != 0);
525 if (protect)
526 out << '(';
527 out << '{' << '\n';
528 ++out.indent_;
529 out << properties_;
530 --out.indent_;
531 out << '\t' << '}';
532 if (protect)
533 out << ')';
534}
535
536void CYPostfix::Output(CYOutput &out, CYFlags flags) const {
537 lhs_->Output(out, Precedence(), CYLeft(flags));
538 out << Operator();
539}
540
541void CYPrefix::Output(CYOutput &out, CYFlags flags) const {
542 const char *name(Operator());
543 out << name;
544 if (Alphabetic())
545 out << ' ';
546 rhs_->Output(out, Precedence(), CYRight(flags));
547}
548
549void CYProgram::Output(CYOutput &out) const {
550 if (statements_ != NULL)
551 statements_->Multiple(out);
552}
553
554void CYProperty::Output(CYOutput &out) const {
555 out << '\t';
556 name_->PropertyName(out);
557 out << ':' << ' ';
558 value_->Output(out, CYPA, CYNoFlags);
559 if (next_ != NULL)
560 out << ',' << '\n' << *next_;
561 else
562 out << '\n';
563}
564
565void CYRegEx::Output(CYOutput &out, CYFlags flags) const {
566 out << Value();
567}
568
569void CYReturn::Output(CYOutput &out, CYFlags flags) const {
570 out << "return";
571 if (value_ != NULL)
572 out << ' ' << *value_;
573 out << ';';
574}
575
576void CYStatement::Multiple(CYOutput &out, CYFlags flags) const {
577 bool first(true);
578 for (const CYStatement *next(this); next != NULL; next = next->next_) {
579 bool last(next->next_ == NULL);
580 CYFlags jacks(first ? last ? flags : CYLeft(flags) : last ? CYCenter(flags) : CYRight(flags));
581 first = false;
582 out << '\t';
583 next->Output(out, jacks);
584 out << '\n';
585 }
586}
587
588void CYStatement::Single(CYOutput &out, CYFlags flags) const {
589 _assert(next_ == NULL);
590 out << '\n';
591 ++out.indent_;
592 out << '\t';
593 Output(out, flags);
594 out << '\n';
595 --out.indent_;
596}
597
598void CYString::Output(CYOutput &out, CYFlags flags) const {
599 std::ostringstream str;
600 CYStringify(str, value_, size_);
601 out << str.str().c_str();
602}
603
604void CYString::PropertyName(CYOutput &out) const {
605 if (const char *word = Word())
606 out << word;
607 else
608 out << *this;
609}
610
611static const char *Reserved_[] = {
612 "false", "null", "true",
613
614 "break", "case", "catch", "continue", "default",
615 "delete", "do", "else", "finally", "for", "function",
616 "if", "in", "instanceof", "new", "return", "switch",
617 "this", "throw", "try", "typeof", "var", "void",
618 "while", "with",
619
620 "debugger", "const",
621
622 "class", "enum", "export", "extends", "import", "super",
623
624 "abstract", "boolean", "byte", "char", "double", "final",
625 "float", "goto", "int", "long", "native", "short",
626 "synchronized", "throws", "transient", "volatile",
627
628 "let", "yield",
629
630 "each",
631
632 NULL
633};
634
635const char *CYString::Word() const {
636 if (size_ == 0 || !WordStartRange_[value_[0]])
637 return NULL;
638 for (size_t i(1); i != size_; ++i)
639 if (!WordEndRange_[value_[i]])
640 return NULL;
641 const char *value(Value());
642 for (const char **reserved(Reserved_); *reserved != NULL; ++reserved)
643 if (strcmp(*reserved, value) == 0)
644 return NULL;
645 return value;
646}
647
648void CYSwitch::Output(CYOutput &out, CYFlags flags) const {
649 out << "switch" << ' ' << '(' << *value_ << ')' << ' ' << '{';
650 out << clauses_;
651 out << '}';
652}
653
654void CYThis::Output(CYOutput &out, CYFlags flags) const {
655 CYWord::Output(out);
656}
657
658namespace cy {
659namespace Syntax {
660
661void Throw::Output(CYOutput &out, CYFlags flags) const {
662 out << "throw";
663 if (value_ != NULL)
664 out << ' ' << *value_;
665 out << ';';
666}
667
668void Try::Output(CYOutput &out, CYFlags flags) const {
669 out << "try" << ' ' << code_ << catch_ << finally_;
670}
671
672} }
673
674void CYVar::Output(CYOutput &out, CYFlags flags) const {
675 out << "var";
676 declarations_->Output(out, flags);
677 out << ';';
678}
679
680void CYVariable::Output(CYOutput &out, CYFlags flags) const {
681 out << *name_;
682}
683
684void CYWhile::Output(CYOutput &out, CYFlags flags) const {
685 out << "while" << '(' << *test_ << ')';
686 code_->Single(out, CYRight(flags));
687}
688
689void CYWith::Output(CYOutput &out, CYFlags flags) const {
690 out << "with" << '(' << *scope_ << ')';
691 code_->Single(out, CYRight(flags));
692}
693
694void CYWord::ClassName(CYOutput &out, bool object) const {
695 if (object)
696 out << "objc_getClass(";
697 out << '"' << Value() << '"';
698 if (object)
699 out << ')';
700}
701
702void CYWord::Output(CYOutput &out) const {
703 out << Value();
704}
705
706void CYWord::PropertyName(CYOutput &out) const {
707 Output(out);
708}